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"
27 #include <sys/errno.h>
29 #include <machine/byte_order.h>
32 #include <security_utilities/crc.h>
33 #include <security_utilities/casts.h>
37 Logically, these should go in /var/run/mds, but we know that /var/db/mds
38 already exists at install time.
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
) {
46 secdebug("MDSPRIVACY","Failed to make directory: %s (%d)", path
, errno
);
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
);
58 SharedMemoryServer::SharedMemoryServer (const char* segmentName
, SegmentOffsetType segmentSize
, uid_t uid
, gid_t gid
) :
59 mSegmentName (segmentName
), mSegmentSize (segmentSize
), mUID(SharedMemoryCommon::fixUID(uid
))
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
);
65 // make the mds directory, just in case it doesn't exist
67 makedir(SharedMemoryCommon::kMDSDirectory
, perm1777
);
68 makedir(SharedMemoryCommon::kMDSMessagesDirectory
, perm0755
);
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
);
76 mFileName
= SharedMemoryCommon::SharedMemoryFilePath(segmentName
, uid
);
79 // clean any old file away
80 unlinkfile(mFileName
.c_str());
83 secdebug("MDSPRIVACY","creating %s",mFileName
.c_str ());
85 mBackingFile
= open (mFileName
.c_str (), O_RDWR
| O_CREAT
| O_EXCL
, perm0600
);
88 mBackingFile
= open (mFileName
.c_str (), O_RDWR
| O_CREAT
| O_EXCL
, S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
93 secdebug("MDSPRIVACY","creation of %s failed", mFileName
.c_str());
97 int rx
= fchown(mBackingFile
, uid
, gid
);
99 secdebug("MDSPRIVACY","chown of %s to %d/%d failed : %d", mFileName
.c_str(), uid
, gid
, rx
);
102 // set the segment size
103 ftruncate (mBackingFile
, segmentSize
);
105 // map it into memory
106 mSegment
= (u_int8_t
*) mmap (NULL
, mSegmentSize
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, mBackingFile
, 0);
108 if (mSegment
== MAP_FAILED
) // can't map the memory?
111 unlinkfile(mFileName
.c_str());
113 mDataPtr
= mDataArea
= mSegment
+ sizeof(SegmentOffsetType
);
114 mDataMax
= mSegment
+ segmentSize
;;
116 SetProducerOffset (0);
120 SharedMemoryServer::~SharedMemoryServer ()
123 if (mSegment
== NULL
)
129 munmap (mSegment
, mSegmentSize
);
133 // mark the segment for deletion
134 unlinkfile(mFileName
.c_str ());
139 const SegmentOffsetType
141 kCRCOffset
= kSegmentLength
+ sizeof(SegmentOffsetType
),
142 kDomainOffset
= kCRCOffset
+ sizeof(SegmentOffsetType
),
143 kEventTypeOffset
= kDomainOffset
+ sizeof(SegmentOffsetType
),
144 kHeaderLength
= kEventTypeOffset
+ sizeof(SegmentOffsetType
) - kCRCOffset
;
146 void SharedMemoryServer::WriteMessage (SegmentOffsetType domain
, SegmentOffsetType event
, const void *message
, SegmentOffsetType messageLength
)
148 // backing file MUST be right size, don't ftruncate() more then needed though to avoid reaching too deep into filesystem
150 if (::fstat(mBackingFile
, &sb
) == 0 && sb
.st_size
!= (off_t
)mSegmentSize
) {
151 ::ftruncate(mBackingFile
, mSegmentSize
);
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
);
162 SegmentOffsetType crc
= CalculateCRC(finalMessage
, messageSize
);
165 WriteOffset(int_cast
<size_t, SegmentOffsetType
>(messageSize
));
171 WriteData (finalMessage
, int_cast
<size_t, SegmentOffsetType
>(messageSize
));
173 // write the data count
174 SetProducerOffset(int_cast
<size_t, SegmentOffsetType
>(mDataPtr
- mDataArea
));
179 const char* SharedMemoryServer::GetSegmentName ()
181 return mSegmentName
.c_str ();
186 size_t SharedMemoryServer::GetSegmentSize ()
192 void SharedMemoryServer::SetProducerOffset (SegmentOffsetType producerCount
)
194 *((SegmentOffsetType
*) mSegment
) = OSSwapHostToBigInt32 (producerCount
);
199 void SharedMemoryServer::WriteOffset(SegmentOffsetType offset
)
202 *((u_int32_t
*) buffer
) = OSSwapHostToBigInt32(offset
);
203 WriteData(buffer
, 4);
208 void SharedMemoryServer::WriteData(const void* data
, SegmentOffsetType length
)
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
);
215 // figure out how many bytes we can write
216 SegmentOffsetType bytesToWrite
= (length
<= bytesToEnd
) ? length
: bytesToEnd
;
218 // move the first part of the data, making sure to skip the producer pointer
219 memcpy (mDataPtr
, dp
, bytesToWrite
);
220 mDataPtr
+= bytesToWrite
;
223 // deduct the bytes just written
224 length
-= bytesToWrite
;
226 if (length
!= 0) // did we wrap around?
228 mDataPtr
= mDataArea
;
229 memcpy (mDataPtr
, dp
, length
);