]> git.saurik.com Git - apple/security.git/blob - securityd/src/SharedMemoryServer.cpp
Security-58286.20.16.tar.gz
[apple/security.git] / securityd / src / SharedMemoryServer.cpp
1 /*
2 * Copyright (c) 2016-2017 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "SharedMemoryServer.h"
25 #include <stdlib.h>
26 #include <sys/mman.h>
27 #include <sys/errno.h>
28 #include <fcntl.h>
29 #include <machine/byte_order.h>
30 #include <string>
31 #include <sys/stat.h>
32 #include <security_utilities/crc.h>
33 #include <security_utilities/casts.h>
34 #include <unistd.h>
35
36 /*
37 Logically, these should go in /var/run/mds, but we know that /var/db/mds
38 already exists at install time.
39 */
40
41 std::string SharedMemoryCommon::SharedMemoryFilePath(const char *segmentName, uid_t uid) {
42 std::string path;
43 uid = SharedMemoryCommon::fixUID(uid);
44 path = SharedMemoryCommon::kMDSMessagesDirectory; // i.e. /private/var/db/mds/messages/
45 if (uid != 0) {
46 path += std::to_string(uid) + "/"; // e.g. /private/var/db/mds/messages/501/
47 }
48
49 path += SharedMemoryCommon::kUserPrefix; // e.g. /var/db/mds/messages/se_
50 path += segmentName; // e.g. /var/db/mds/messages/501/se_SecurityMessages
51 return path;
52 }
53
54 static bool makedir(const char *path, mode_t mode) {
55 // Returns true on success. Primarily to centralize logging
56 if (::mkdir(path, mode)==0 || errno==EEXIST) {
57 return true;
58 } else {
59 secdebug("MDSPRIVACY","Failed to make directory: %s (%d)", path, errno);
60 return false;
61 }
62 }
63
64 static void unlinkfile(const char *path) {
65 // Primarily to centralize logging
66 if (::unlink(path)==-1) {
67 secdebug("MDSPRIVACY","Failed to unlink file: %s (%d)", path, errno);
68 }
69 }
70
71 SharedMemoryServer::SharedMemoryServer (const char* segmentName, SegmentOffsetType segmentSize, uid_t uid, gid_t gid) :
72 mSegmentName (segmentName), mSegmentSize (segmentSize), mUID(SharedMemoryCommon::fixUID(uid))
73 {
74 const mode_t perm1777 = S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO;
75 const mode_t perm0755 = S_IRWXU | (S_IRGRP | S_IXGRP) | (S_IROTH | S_IXOTH);
76 const mode_t perm0600 = (S_IRUSR | S_IWUSR);
77
78 // make the mds directory, just in case it doesn't exist
79 if (mUID == 0) {
80 makedir(SharedMemoryCommon::kMDSDirectory, perm1777);
81 makedir(SharedMemoryCommon::kMDSMessagesDirectory, perm0755);
82 } else {
83 // Assume kMDSMessagesDirectory was created first by securityd
84 std::string uidstr = std::to_string(mUID);
85 std::string upath = SharedMemoryCommon::kMDSMessagesDirectory;
86 upath += "/" + uidstr;
87 makedir(upath.c_str(), perm0755);
88 }
89 mFileName = SharedMemoryCommon::SharedMemoryFilePath(segmentName, uid);
90
91 // make the file name
92 // clean any old file away
93 unlinkfile(mFileName.c_str());
94
95 // open the file
96 secdebug("MDSPRIVACY","creating %s",mFileName.c_str ());
97 if(mUID != 0) {
98 mBackingFile = open (mFileName.c_str (), O_RDWR | O_CREAT | O_EXCL, perm0600);
99 }
100 else {
101 mBackingFile = open (mFileName.c_str (), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
102 }
103
104 if (mBackingFile < 0)
105 {
106 secdebug("MDSPRIVACY","creation of %s failed", mFileName.c_str());
107 return;
108 }
109
110 int rx = fchown(mBackingFile, uid, gid);
111 if (rx) {
112 secdebug("MDSPRIVACY","chown of %s to %d/%d failed : %d", mFileName.c_str(), uid, gid, rx);
113 }
114
115 // set the segment size
116 ftruncate (mBackingFile, segmentSize);
117
118 // map it into memory
119 mSegment = (u_int8_t*) mmap (NULL, mSegmentSize, PROT_READ | PROT_WRITE, MAP_SHARED, mBackingFile, 0);
120
121 if (mSegment == MAP_FAILED) // can't map the memory?
122 {
123 mSegment = NULL;
124 unlinkfile(mFileName.c_str());
125 } else {
126 mDataPtr = mDataArea = mSegment + sizeof(SegmentOffsetType);
127 mDataMax = mSegment + segmentSize;;
128
129 SetProducerOffset (0);
130 }
131 }
132
133 SharedMemoryServer::~SharedMemoryServer ()
134 {
135 // go away
136 if (mSegment == NULL)
137 {
138 return;
139 }
140
141 // get out of memory
142 munmap (mSegment, mSegmentSize);
143
144 close(mBackingFile);
145
146 // mark the segment for deletion
147 unlinkfile(mFileName.c_str ());
148 }
149
150
151
152 const SegmentOffsetType
153 kSegmentLength = 0,
154 kCRCOffset = kSegmentLength + sizeof(SegmentOffsetType),
155 kDomainOffset = kCRCOffset + sizeof(SegmentOffsetType),
156 kEventTypeOffset = kDomainOffset + sizeof(SegmentOffsetType),
157 kHeaderLength = kEventTypeOffset + sizeof(SegmentOffsetType) - kCRCOffset;
158
159 void SharedMemoryServer::WriteMessage (SegmentOffsetType domain, SegmentOffsetType event, const void *message, SegmentOffsetType messageLength)
160 {
161 // backing file MUST be right size, don't ftruncate() more then needed though to avoid reaching too deep into filesystem
162 struct stat sb;
163 if (::fstat(mBackingFile, &sb) == 0 && sb.st_size != (off_t)mSegmentSize) {
164 ::ftruncate(mBackingFile, mSegmentSize);
165 }
166
167 // assemble the final message
168 ssize_t messageSize = kHeaderLength + messageLength;
169 u_int8_t finalMessage[messageSize];
170 SegmentOffsetType *fm = (SegmentOffsetType*) finalMessage;
171 fm[0] = OSSwapHostToBigInt32(domain);
172 fm[1] = OSSwapHostToBigInt32(event);
173 memcpy(&fm[2], message, messageLength);
174
175 SegmentOffsetType crc = CalculateCRC(finalMessage, messageSize);
176
177 // write the length
178 WriteOffset(int_cast<size_t, SegmentOffsetType>(messageSize));
179
180 // write the crc
181 WriteOffset(crc);
182
183 // write the data
184 WriteData (finalMessage, int_cast<size_t, SegmentOffsetType>(messageSize));
185
186 // write the data count
187 SetProducerOffset(int_cast<size_t, SegmentOffsetType>(mDataPtr - mDataArea));
188 }
189
190
191
192 const char* SharedMemoryServer::GetSegmentName ()
193 {
194 return mSegmentName.c_str ();
195 }
196
197
198
199 size_t SharedMemoryServer::GetSegmentSize ()
200 {
201 return mSegmentSize;
202 }
203
204
205 void SharedMemoryServer::SetProducerOffset (SegmentOffsetType producerCount)
206 {
207 *((SegmentOffsetType*) mSegment) = OSSwapHostToBigInt32 (producerCount);
208 }
209
210
211
212 void SharedMemoryServer::WriteOffset(SegmentOffsetType offset)
213 {
214 u_int8_t buffer[4];
215 *((u_int32_t*) buffer) = OSSwapHostToBigInt32(offset);
216 WriteData(buffer, 4);
217 }
218
219
220
221 void SharedMemoryServer::WriteData(const void* data, SegmentOffsetType length)
222 {
223 // figure out where in the buffer we actually need to write the data
224 // figure out how many bytes we can write without overflowing the buffer
225 const u_int8_t* dp = (const u_int8_t*) data;
226 SegmentOffsetType bytesToEnd = int_cast<ptrdiff_t, SegmentOffsetType>(mDataMax - mDataPtr);
227
228 // figure out how many bytes we can write
229 SegmentOffsetType bytesToWrite = (length <= bytesToEnd) ? length : bytesToEnd;
230
231 // move the first part of the data, making sure to skip the producer pointer
232 memcpy (mDataPtr, dp, bytesToWrite);
233 mDataPtr += bytesToWrite;
234 dp += bytesToWrite;
235
236 // deduct the bytes just written
237 length -= bytesToWrite;
238
239 if (length != 0) // did we wrap around?
240 {
241 mDataPtr = mDataArea;
242 memcpy (mDataPtr, dp, length);
243 mDataPtr += length;
244 }
245 }