SharedMemoryClient.cpp
1 #include <sys/mman.h> 2 #include <sys/types.h> 3 #include <sys/stat.h> 4 #include <unistd.h> 5 #include <fcntl.h> 6 #include <architecture/byte_order.h> 7 #include <security_cdsa_utilities/cssmdb.h> 8 #include "SharedMemoryClient.h" 9 #include <string> 10 #include <security_utilities/crc.h> 11 #include <securityd_client/ssnotify.h> 12 #include <Security/SecKeychain.h> 13 14 using namespace Security; 15 16 //================================================================================= 17 // SharedMemoryClient 18 //================================================================================= 19 20 #if !defined(NDEBUG) 21 static std::string unixerrorstr(int errnum) { 22 string errstr; 23 char buf[1024]; 24 // might return ERANGE 25 /* int rx = */ strerror_r(errnum, buf, sizeof(buf)); 26 errstr = string(buf); 27 errstr += "(" + to_string(errnum) + ")"; 28 return errstr; 29 } 30 #endif 31 32 SharedMemoryClient::SharedMemoryClient (const char* segmentName, SegmentOffsetType segmentSize, uid_t uid) 33 { 34 StLock<Mutex> _(mMutex); 35 36 mSegmentName = segmentName; 37 mSegmentSize = segmentSize; 38 mSegment = (u_int8_t*) MAP_FAILED; 39 mDataArea = mDataPtr = 0; 40 mUID = uid; 41 42 secdebug("MDSPRIVACY","[%03d] creating SharedMemoryClient with segmentName %s, size: %d", mUID, segmentName, segmentSize); 43 44 if (segmentSize < sizeof(u_int32_t)) 45 return; 46 47 // make the name 48 int segmentDescriptor; 49 { 50 std::string name(SharedMemoryCommon::SharedMemoryFilePath(mSegmentName.c_str(), mUID)); 51 52 // make a connection to the shared memory block 53 segmentDescriptor = open (name.c_str(), O_RDONLY, S_IROTH); 54 if (segmentDescriptor < 0) // error on opening the shared memory segment? 55 { 56 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient open of %s failed: %s", mUID, name.c_str(), unixerrorstr(errno).c_str()); 57 // CssmError::throwMe (CSSM_ERRCODE_INTERNAL_ERROR); 58 return; 59 } 60 } 61 62 // check that the file size is large enough to support operations 63 struct stat statResult = {}; 64 int result = fstat(segmentDescriptor, &statResult); 65 if(result) { 66 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient fstat failed: %d/%s", mUID, result, unixerrorstr(errno).c_str()); 67 UnixError::throwMe(errno); 68 } 69 70 off_t sz = statResult.st_size; 71 if(sz < sizeof(SegmentOffsetType)) { 72 close(segmentDescriptor); 73 return; 74 } 75 76 if(sz > 4*segmentSize) { 77 // File is too ridiculously large. Quit. 78 close(segmentDescriptor); 79 return; 80 } 81 82 // map the segment into place 83 mSegment = (u_int8_t*) mmap (NULL, segmentSize, PROT_READ, MAP_SHARED, segmentDescriptor, 0); 84 close (segmentDescriptor); 85 86 if (mSegment == MAP_FAILED) 87 { 88 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient mmap failed: %d", mUID, errno); 89 return; 90 } 91 92 mDataArea = mSegment + sizeof (SegmentOffsetType); 93 mDataMax = mSegment + sz; 94 mDataPtr = mDataArea + GetProducerCount (); 95 } 96 97 98 99 SharedMemoryClient::~SharedMemoryClient () 100 { 101 if (!uninitialized()) { 102 StLock<Mutex> _(mMutex); 103 munmap (mSegment, mSegmentSize); 104 } 105 } 106 107 108 SegmentOffsetType SharedMemoryClient::GetProducerCount () 109 { 110 if (uninitialized()) { 111 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient::GetProducerCount uninitialized", mUID); 112 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 113 } 114 if( ((u_int8_t*) (((u_int32_t*) mSegment) + 1)) > mDataMax) { 115 // Check we can actually read this u_int32_t 116 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient::GetProducerCount uint > mDataMax", mUID); 117 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 118 } 119 120 SegmentOffsetType offset = OSSwapBigToHostInt32 (*(u_int32_t*) mSegment); 121 if (&mSegment[offset] >= mDataMax) { 122 secdebug("MDSPRIVACY","[%03d] SharedMemoryClient::GetProducerCount offset > mDataMax", mUID); 123 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 124 } 125 126 return offset; 127 } 128 129 void SharedMemoryClient::ReadData (void* buffer, SegmentOffsetType length) 130 { 131 if (uninitialized()) { 132 secdebug("MDSPRIVACY","[%03d] ReadData mSegment fail uninitialized: %p", mUID, mSegment); 133 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 134 } 135 136 u_int8_t* bptr = (u_int8_t*) buffer; 137 138 SegmentOffsetType bytesToEnd = (SegmentOffsetType)(mDataMax - mDataPtr); 139 140 // figure out how many bytes we can read 141 SegmentOffsetType bytesToRead = (length <= bytesToEnd) ? length : bytesToEnd; 142 143 // move the first part of the data 144 memcpy (bptr, mDataPtr, bytesToRead); 145 bptr += bytesToRead; 146 147 // see if we have anything else to read 148 mDataPtr += bytesToRead; 149 150 length -= bytesToRead; 151 if (length != 0) 152 { 153 mDataPtr = mDataArea; 154 memcpy(bptr, mDataPtr, length); 155 mDataPtr += length; 156 } 157 } 158 159 160 161 SegmentOffsetType SharedMemoryClient::ReadOffset() 162 { 163 SegmentOffsetType offset; 164 ReadData(&offset, sizeof(SegmentOffsetType)); 165 offset = OSSwapBigToHostInt32 (offset); 166 return offset; 167 } 168 169 170 171 bool SharedMemoryClient::ReadMessage (void* message, SegmentOffsetType &length, UnavailableReason &ur) 172 { 173 StLock<Mutex> _(mMutex); 174 175 if (uninitialized()) { 176 secdebug("MDSPRIVACY","[%03d] ReadMessage mSegment fail uninitialized: %p", mUID, mSegment); 177 CssmError::throwMe(CSSM_ERRCODE_INTERNAL_ERROR); 178 } 179 180 ur = kURNone; 181 182 size_t offset = mDataPtr - mDataArea; 183 if (offset == GetProducerCount()) 184 { 185 secdebug("MDSPRIVACY","[%03d] ReadMessage GetProducerCount()", mUID); 186 ur = kURNoMessage; 187 return false; 188 } 189 190 // get the length of the message in the buffer 191 length = ReadOffset(); 192 193 // we have the possibility that data is correct, figure out where the data is actually located 194 // get the length of the message stored there 195 if (length == 0 || length >= kPoolAvailableForData) 196 { 197 secdebug("MDSPRIVACY","[%03d] ReadMessage length error: %d", mUID, length); 198 ur = (length == 0) ? kURNoMessage : kURBufferCorrupt; 199 200 // something's gone wrong, reset. 201 mDataPtr = mDataArea + GetProducerCount (); 202 return false; 203 } 204 205 // read the crc 206 SegmentOffsetType crc = ReadOffset(); 207 208 // read the data into the buffer 209 ReadData (message, length); 210 211 // calculate the CRC 212 SegmentOffsetType crc2 = CalculateCRC((u_int8_t*) message, length); 213 if (crc != crc2) 214 { 215 ur = kURBufferCorrupt; 216 mDataPtr = mDataArea + GetProducerCount (); 217 return false; 218 } 219 220 return true; 221 } 222 223 //================================================================================= 224 // SharedMemoryCommon 225 //================================================================================= 226 227 std::string SharedMemoryCommon::SharedMemoryFilePath(const char *segmentName, uid_t uid) { 228 std::string path; 229 uid = SharedMemoryCommon::fixUID(uid); 230 path = SharedMemoryCommon::kMDSMessagesDirectory; // i.e. /private/var/db/mds/messages/ 231 if (uid != 0) { 232 path += std::to_string(uid) + "/"; // e.g. /private/var/db/mds/messages/501/ 233 } 234 235 path += SharedMemoryCommon::kUserPrefix; // e.g. /var/db/mds/messages/se_ 236 path += segmentName; // e.g. /var/db/mds/messages/501/se_SecurityMessages 237 return path; 238 } 239 240 std::string SharedMemoryCommon::notificationDescription(int domain, int event) { 241 string domainstr, eventstr; 242 243 switch (domain) { 244 case Security::SecurityServer::kNotificationDomainAll: domainstr = "all"; break; 245 case Security::SecurityServer::kNotificationDomainDatabase: domainstr = "database"; break; 246 case Security::SecurityServer::kNotificationDomainPCSC: domainstr = "pcsc"; break; 247 case Security::SecurityServer::kNotificationDomainCDSA: domainstr = "CDSA"; break; 248 default: 249 domainstr = "unknown"; 250 break; 251 } 252 253 switch (event) { 254 case kSecLockEvent: eventstr = "lock"; break; 255 case kSecUnlockEvent: eventstr = "unlock"; break; 256 case kSecAddEvent: eventstr = "add"; break; 257 case kSecDeleteEvent: eventstr = "delete"; break; 258 case kSecUpdateEvent: eventstr = "update"; break; 259 case kSecPasswordChangedEvent: eventstr = "passwordChange"; break; 260 case kSecDefaultChangedEvent: eventstr = "defaultChange"; break; 261 case kSecDataAccessEvent: eventstr = "dataAccess"; break; 262 case kSecKeychainListChangedEvent: eventstr = "listChange"; break; 263 case kSecTrustSettingsChangedEvent: eventstr = "trustSettings"; break; 264 default: 265 domainstr = "unknown"; 266 break; 267 } 268 269 return "Domain: " + domainstr + ", Event: " + eventstr; 270 }