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