]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurityd/lib/SharedMemoryClient.cpp
Security-59306.11.20.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 #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 }