]> git.saurik.com Git - apple/security.git/blob - securityd/src/SharedMemoryServer.cpp
Security-58286.200.222.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 static bool makedir(const char *path, mode_t mode) {
42 // Returns true on success. Primarily to centralize logging
43 if (::mkdir(path, mode)==0 || errno==EEXIST) {
44 return true;
45 } else {
46 secdebug("MDSPRIVACY","Failed to make directory: %s (%d)", path, errno);
47 return false;
48 }
49 }
50
51 static void unlinkfile(const char *path) {
52 // Primarily to centralize logging
53 if (::unlink(path)==-1) {
54 secdebug("MDSPRIVACY","Failed to unlink file: %s (%d)", path, errno);
55 }
56 }
57
58 SharedMemoryServer::SharedMemoryServer (const char* segmentName, SegmentOffsetType segmentSize, uid_t uid, gid_t gid) :
59 mSegmentName (segmentName), mSegmentSize (segmentSize), mUID(SharedMemoryCommon::fixUID(uid))
60 {
61 const mode_t perm1777 = S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO;
62 const mode_t perm0755 = S_IRWXU | (S_IRGRP | S_IXGRP) | (S_IROTH | S_IXOTH);
63 const mode_t perm0600 = (S_IRUSR | S_IWUSR);
64
65 // make the mds directory, just in case it doesn't exist
66 if (mUID == 0) {
67 makedir(SharedMemoryCommon::kMDSDirectory, perm1777);
68 makedir(SharedMemoryCommon::kMDSMessagesDirectory, perm0755);
69 } else {
70 // Assume kMDSMessagesDirectory was created first by securityd
71 std::string uidstr = std::to_string(mUID);
72 std::string upath = SharedMemoryCommon::kMDSMessagesDirectory;
73 upath += "/" + uidstr;
74 makedir(upath.c_str(), perm0755);
75 }
76 mFileName = SharedMemoryCommon::SharedMemoryFilePath(segmentName, uid);
77
78 // make the file name
79 // clean any old file away
80 unlinkfile(mFileName.c_str());
81
82 // open the file
83 secdebug("MDSPRIVACY","creating %s",mFileName.c_str ());
84 if(mUID != 0) {
85 mBackingFile = open (mFileName.c_str (), O_RDWR | O_CREAT | O_EXCL, perm0600);
86 }
87 else {
88 mBackingFile = open (mFileName.c_str (), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
89 }
90
91 if (mBackingFile < 0)
92 {
93 secdebug("MDSPRIVACY","creation of %s failed", mFileName.c_str());
94 return;
95 }
96
97 int rx = fchown(mBackingFile, uid, gid);
98 if (rx) {
99 secdebug("MDSPRIVACY","chown of %s to %d/%d failed : %d", mFileName.c_str(), uid, gid, rx);
100 }
101
102 // set the segment size
103 ftruncate (mBackingFile, segmentSize);
104
105 // map it into memory
106 mSegment = (u_int8_t*) mmap (NULL, mSegmentSize, PROT_READ | PROT_WRITE, MAP_SHARED, mBackingFile, 0);
107
108 if (mSegment == MAP_FAILED) // can't map the memory?
109 {
110 mSegment = NULL;
111 unlinkfile(mFileName.c_str());
112 } else {
113 mDataPtr = mDataArea = mSegment + sizeof(SegmentOffsetType);
114 mDataMax = mSegment + segmentSize;;
115
116 SetProducerOffset (0);
117 }
118 }
119
120 SharedMemoryServer::~SharedMemoryServer ()
121 {
122 // go away
123 if (mSegment == NULL)
124 {
125 return;
126 }
127
128 // get out of memory
129 munmap (mSegment, mSegmentSize);
130
131 close(mBackingFile);
132
133 // mark the segment for deletion
134 unlinkfile(mFileName.c_str ());
135 }
136
137
138
139 const SegmentOffsetType
140 kSegmentLength = 0,
141 kCRCOffset = kSegmentLength + sizeof(SegmentOffsetType),
142 kDomainOffset = kCRCOffset + sizeof(SegmentOffsetType),
143 kEventTypeOffset = kDomainOffset + sizeof(SegmentOffsetType),
144 kHeaderLength = kEventTypeOffset + sizeof(SegmentOffsetType) - kCRCOffset;
145
146 void SharedMemoryServer::WriteMessage (SegmentOffsetType domain, SegmentOffsetType event, const void *message, SegmentOffsetType messageLength)
147 {
148 // backing file MUST be right size, don't ftruncate() more then needed though to avoid reaching too deep into filesystem
149 struct stat sb;
150 if (::fstat(mBackingFile, &sb) == 0 && sb.st_size != (off_t)mSegmentSize) {
151 ::ftruncate(mBackingFile, mSegmentSize);
152 }
153
154 // assemble the final message
155 ssize_t messageSize = kHeaderLength + messageLength;
156 u_int8_t finalMessage[messageSize];
157 SegmentOffsetType *fm = (SegmentOffsetType*) finalMessage;
158 fm[0] = OSSwapHostToBigInt32(domain);
159 fm[1] = OSSwapHostToBigInt32(event);
160 memcpy(&fm[2], message, messageLength);
161
162 SegmentOffsetType crc = CalculateCRC(finalMessage, messageSize);
163
164 // write the length
165 WriteOffset(int_cast<size_t, SegmentOffsetType>(messageSize));
166
167 // write the crc
168 WriteOffset(crc);
169
170 // write the data
171 WriteData (finalMessage, int_cast<size_t, SegmentOffsetType>(messageSize));
172
173 // write the data count
174 SetProducerOffset(int_cast<size_t, SegmentOffsetType>(mDataPtr - mDataArea));
175 }
176
177
178
179 const char* SharedMemoryServer::GetSegmentName ()
180 {
181 return mSegmentName.c_str ();
182 }
183
184
185
186 size_t SharedMemoryServer::GetSegmentSize ()
187 {
188 return mSegmentSize;
189 }
190
191
192 void SharedMemoryServer::SetProducerOffset (SegmentOffsetType producerCount)
193 {
194 *((SegmentOffsetType*) mSegment) = OSSwapHostToBigInt32 (producerCount);
195 }
196
197
198
199 void SharedMemoryServer::WriteOffset(SegmentOffsetType offset)
200 {
201 u_int8_t buffer[4];
202 *((u_int32_t*) buffer) = OSSwapHostToBigInt32(offset);
203 WriteData(buffer, 4);
204 }
205
206
207
208 void SharedMemoryServer::WriteData(const void* data, SegmentOffsetType length)
209 {
210 // figure out where in the buffer we actually need to write the data
211 // figure out how many bytes we can write without overflowing the buffer
212 const u_int8_t* dp = (const u_int8_t*) data;
213 SegmentOffsetType bytesToEnd = int_cast<ptrdiff_t, SegmentOffsetType>(mDataMax - mDataPtr);
214
215 // figure out how many bytes we can write
216 SegmentOffsetType bytesToWrite = (length <= bytesToEnd) ? length : bytesToEnd;
217
218 // move the first part of the data, making sure to skip the producer pointer
219 memcpy (mDataPtr, dp, bytesToWrite);
220 mDataPtr += bytesToWrite;
221 dp += bytesToWrite;
222
223 // deduct the bytes just written
224 length -= bytesToWrite;
225
226 if (length != 0) // did we wrap around?
227 {
228 mDataPtr = mDataArea;
229 memcpy (mDataPtr, dp, length);
230 mDataPtr += length;
231 }
232 }