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