2 * Copyright (c) 2016-2017 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
24 #include "SharedMemoryServer.h"
28 #include <machine/byte_order.h>
31 #include <security_utilities/crc.h>
32 #include <security_utilities/casts.h>
36 Logically, these should go in /var/run/mds, but we know that /var/db/mds
37 already exists at install time.
40 std::string
SharedMemoryCommon::SharedMemoryFilePath(const char *segmentName
, uid_t uid
) {
42 uid
= SharedMemoryCommon::fixUID(uid
);
43 path
= SharedMemoryCommon::kMDSMessagesDirectory
; // i.e. /private/var/db/mds/messages/
45 path
+= std::to_string(uid
) + "/"; // e.g. /private/var/db/mds/messages/501/
48 path
+= SharedMemoryCommon::kUserPrefix
; // e.g. /var/db/mds/messages/se_
49 path
+= segmentName
; // e.g. /var/db/mds/messages/501/se_SecurityMessages
53 SharedMemoryServer::SharedMemoryServer (const char* segmentName
, SegmentOffsetType segmentSize
, uid_t uid
, gid_t gid
) :
54 mSegmentName (segmentName
), mSegmentSize (segmentSize
), mUID(SharedMemoryCommon::fixUID(uid
))
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
);
60 // make the mds directory, just in case it doesn't exist
62 mkdir(SharedMemoryCommon::kMDSDirectory
, perm1777
);
63 mkdir(SharedMemoryCommon::kMDSMessagesDirectory
, perm0755
);
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
);
71 mFileName
= SharedMemoryCommon::SharedMemoryFilePath(segmentName
, uid
);
74 // clean any old file away
75 unlink(mFileName
.c_str());
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
);
82 secdebug("MDSPRIVACY","creation of %s failed", mFileName
.c_str());
86 int rx
= chown(mFileName
.c_str (), uid
, gid
);
88 secdebug("MDSPRIVACY","chown of %s to %d/%d failed : %d", mFileName
.c_str(), uid
, gid
, rx
);
92 int rx
= fchmod(mBackingFile
, perm0600
);
94 secdebug("MDSPRIVACY","chmod of %s to %x failed : %d", mFileName
.c_str(), perm0600
, rx
);
98 // set the segment size
99 ftruncate (mBackingFile
, segmentSize
);
101 // map it into memory
102 mSegment
= (u_int8_t
*) mmap (NULL
, mSegmentSize
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, mBackingFile
, 0);
104 if (mSegment
== MAP_FAILED
) // can't map the memory?
107 unlink(mFileName
.c_str());
109 mDataPtr
= mDataArea
= mSegment
+ sizeof(SegmentOffsetType
);
110 mDataMax
= mSegment
+ segmentSize
;;
112 SetProducerOffset (0);
116 SharedMemoryServer::~SharedMemoryServer ()
119 if (mSegment
== NULL
)
125 munmap (mSegment
, mSegmentSize
);
129 // mark the segment for deletion
130 unlink (mFileName
.c_str ());
135 const SegmentOffsetType
137 kCRCOffset
= kSegmentLength
+ sizeof(SegmentOffsetType
),
138 kDomainOffset
= kCRCOffset
+ sizeof(SegmentOffsetType
),
139 kEventTypeOffset
= kDomainOffset
+ sizeof(SegmentOffsetType
),
140 kHeaderLength
= kEventTypeOffset
+ sizeof(SegmentOffsetType
) - kCRCOffset
;
142 void SharedMemoryServer::WriteMessage (SegmentOffsetType domain
, SegmentOffsetType event
, const void *message
, SegmentOffsetType messageLength
)
144 // backing file MUST be right size
145 ftruncate (mBackingFile
, mSegmentSize
);
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
);
155 SegmentOffsetType crc
= CalculateCRC(finalMessage
, messageSize
);
158 WriteOffset(int_cast
<size_t, SegmentOffsetType
>(messageSize
));
164 WriteData (finalMessage
, int_cast
<size_t, SegmentOffsetType
>(messageSize
));
166 // write the data count
167 SetProducerOffset(int_cast
<size_t, SegmentOffsetType
>(mDataPtr
- mDataArea
));
172 const char* SharedMemoryServer::GetSegmentName ()
174 return mSegmentName
.c_str ();
179 size_t SharedMemoryServer::GetSegmentSize ()
185 void SharedMemoryServer::SetProducerOffset (SegmentOffsetType producerCount
)
187 *((SegmentOffsetType
*) mSegment
) = OSSwapHostToBigInt32 (producerCount
);
192 void SharedMemoryServer::WriteOffset(SegmentOffsetType offset
)
195 *((u_int32_t
*) buffer
) = OSSwapHostToBigInt32(offset
);
196 WriteData(buffer
, 4);
201 void SharedMemoryServer::WriteData(const void* data
, SegmentOffsetType length
)
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
);
208 // figure out how many bytes we can write
209 SegmentOffsetType bytesToWrite
= (length
<= bytesToEnd
) ? length
: bytesToEnd
;
211 // move the first part of the data, making sure to skip the producer pointer
212 memcpy (mDataPtr
, dp
, bytesToWrite
);
213 mDataPtr
+= bytesToWrite
;
216 // deduct the bytes just written
217 length
-= bytesToWrite
;
219 if (length
!= 0) // did we wrap around?
221 mDataPtr
= mDataArea
;
222 memcpy (mDataPtr
, dp
, length
);