SharedMemoryServer.cpp [plain text]
#include "SharedMemoryServer.h"
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <machine/byte_order.h>
#include <string>
#include <sys/stat.h>
#include <security_utilities/crc.h>
#include <security_utilities/casts.h>
#include <unistd.h>
static bool makedir(const char *path, mode_t mode) {
if (::mkdir(path, mode)==0 || errno==EEXIST) {
return true;
} else {
secdebug("MDSPRIVACY","Failed to make directory: %s (%d)", path, errno);
return false;
}
}
static void unlinkfile(const char *path) {
if (::unlink(path)==-1) {
secdebug("MDSPRIVACY","Failed to unlink file: %s (%d)", path, errno);
}
}
SharedMemoryServer::SharedMemoryServer (const char* segmentName, SegmentOffsetType segmentSize, uid_t uid, gid_t gid) :
mSegmentName (segmentName), mSegmentSize (segmentSize), mUID(SharedMemoryCommon::fixUID(uid))
{
const mode_t perm1777 = S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO;
const mode_t perm0755 = S_IRWXU | (S_IRGRP | S_IXGRP) | (S_IROTH | S_IXOTH);
const mode_t perm0600 = (S_IRUSR | S_IWUSR);
if (mUID == 0) {
makedir(SharedMemoryCommon::kMDSDirectory, perm1777);
makedir(SharedMemoryCommon::kMDSMessagesDirectory, perm0755);
} else {
std::string uidstr = std::to_string(mUID);
std::string upath = SharedMemoryCommon::kMDSMessagesDirectory;
upath += "/" + uidstr;
makedir(upath.c_str(), perm0755);
}
mFileName = SharedMemoryCommon::SharedMemoryFilePath(segmentName, uid);
unlinkfile(mFileName.c_str());
secdebug("MDSPRIVACY","creating %s",mFileName.c_str ());
if(mUID != 0) {
mBackingFile = open (mFileName.c_str (), O_RDWR | O_CREAT | O_EXCL, perm0600);
}
else {
mBackingFile = open (mFileName.c_str (), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
}
if (mBackingFile < 0)
{
secdebug("MDSPRIVACY","creation of %s failed", mFileName.c_str());
return;
}
int rx = fchown(mBackingFile, uid, gid);
if (rx) {
secdebug("MDSPRIVACY","chown of %s to %d/%d failed : %d", mFileName.c_str(), uid, gid, rx);
}
ftruncate (mBackingFile, segmentSize);
mSegment = (u_int8_t*) mmap (NULL, mSegmentSize, PROT_READ | PROT_WRITE, MAP_SHARED, mBackingFile, 0);
if (mSegment == MAP_FAILED) {
mSegment = NULL;
unlinkfile(mFileName.c_str());
} else {
mDataPtr = mDataArea = mSegment + sizeof(SegmentOffsetType);
mDataMax = mSegment + segmentSize;;
SetProducerOffset (0);
}
}
SharedMemoryServer::~SharedMemoryServer ()
{
if (mSegment == NULL)
{
return;
}
munmap (mSegment, mSegmentSize);
close(mBackingFile);
unlinkfile(mFileName.c_str ());
}
const SegmentOffsetType
kSegmentLength = 0,
kCRCOffset = kSegmentLength + sizeof(SegmentOffsetType),
kDomainOffset = kCRCOffset + sizeof(SegmentOffsetType),
kEventTypeOffset = kDomainOffset + sizeof(SegmentOffsetType),
kHeaderLength = kEventTypeOffset + sizeof(SegmentOffsetType) - kCRCOffset;
void SharedMemoryServer::WriteMessage (SegmentOffsetType domain, SegmentOffsetType event, const void *message, SegmentOffsetType messageLength)
{
struct stat sb;
if (::fstat(mBackingFile, &sb) == 0 && sb.st_size != (off_t)mSegmentSize) {
::ftruncate(mBackingFile, mSegmentSize);
}
ssize_t messageSize = kHeaderLength + messageLength;
u_int8_t finalMessage[messageSize];
SegmentOffsetType *fm = (SegmentOffsetType*) finalMessage;
fm[0] = OSSwapHostToBigInt32(domain);
fm[1] = OSSwapHostToBigInt32(event);
memcpy(&fm[2], message, messageLength);
SegmentOffsetType crc = CalculateCRC(finalMessage, messageSize);
WriteOffset(int_cast<size_t, SegmentOffsetType>(messageSize));
WriteOffset(crc);
WriteData (finalMessage, int_cast<size_t, SegmentOffsetType>(messageSize));
SetProducerOffset(int_cast<size_t, SegmentOffsetType>(mDataPtr - mDataArea));
}
const char* SharedMemoryServer::GetSegmentName ()
{
return mSegmentName.c_str ();
}
size_t SharedMemoryServer::GetSegmentSize ()
{
return mSegmentSize;
}
void SharedMemoryServer::SetProducerOffset (SegmentOffsetType producerCount)
{
*((SegmentOffsetType*) mSegment) = OSSwapHostToBigInt32 (producerCount);
}
void SharedMemoryServer::WriteOffset(SegmentOffsetType offset)
{
u_int8_t buffer[4];
*((u_int32_t*) buffer) = OSSwapHostToBigInt32(offset);
WriteData(buffer, 4);
}
void SharedMemoryServer::WriteData(const void* data, SegmentOffsetType length)
{
const u_int8_t* dp = (const u_int8_t*) data;
SegmentOffsetType bytesToEnd = int_cast<ptrdiff_t, SegmentOffsetType>(mDataMax - mDataPtr);
SegmentOffsetType bytesToWrite = (length <= bytesToEnd) ? length : bytesToEnd;
memcpy (mDataPtr, dp, bytesToWrite);
mDataPtr += bytesToWrite;
dp += bytesToWrite;
length -= bytesToWrite;
if (length != 0) {
mDataPtr = mDataArea;
memcpy (mDataPtr, dp, length);
mDataPtr += length;
}
}