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