Skip to content

Commit

Permalink
Mac kext: Dynamically alloc virtualisation root array & resize when f…
Browse files Browse the repository at this point in the history
…ull.
  • Loading branch information
pmj committed Oct 3, 2018
1 parent 0b7d992 commit 867f547
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 28 deletions.
90 changes: 63 additions & 27 deletions ProjFS.Mac/PrjFSKext/PrjFSKext/VirtualizationRoots.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,33 +29,31 @@ struct VirtualizationRoot

// TODO(Mac): this should eventually be entirely diagnostic and not used for decisions
char path[PrjFSMaxPath];

int32_t index;
};

static RWLock s_rwLock = {};

// Arbitrary choice, but prevents user space attacker from causing
// allocation of too much wired kernel memory.
static const size_t MaxVirtualizationRoots = 128;

static VirtualizationRoot s_virtualizationRoots[MaxVirtualizationRoots] = {};
// Current length of the s_virtualizationRoots array
static uint16_t s_maxVirtualizationRoots = 0;
static VirtualizationRoot* s_virtualizationRoots = nullptr;

static VirtualizationRootHandle FindRootAtVnode_Locked(vnode_t vnode, uint32_t vid, VnodeFsidInode fileId);
static VirtualizationRootHandle FindUnusedIndex_Locked();
static VirtualizationRootHandle InsertVirtualizationRoot_Locked(PrjFSProviderUserClient* userClient, pid_t clientPID, vnode_t vnode, uint32_t vid, VnodeFsidInode persistentIds, const char* path);

bool VirtualizationRoot_IsOnline(VirtualizationRootHandle rootIndex)
{
if (rootIndex < 0 || rootIndex >= MaxVirtualizationRoots)
if (rootIndex < 0)
{
return false;
}

bool result;
RWLock_AcquireShared(s_rwLock);
{
result = (nullptr != s_virtualizationRoots[rootIndex].providerUserClient);
result =
(rootIndex < s_maxVirtualizationRoots)
&& (nullptr != s_virtualizationRoots[rootIndex].providerUserClient);
}
RWLock_ReleaseShared(s_rwLock);

Expand All @@ -68,7 +66,7 @@ bool VirtualizationRoot_PIDMatchesProvider(VirtualizationRootHandle rootIndex, p
RWLock_AcquireShared(s_rwLock);
{
result =
(rootIndex >= 0 && rootIndex < MaxVirtualizationRoots)
(rootIndex >= 0 && rootIndex < s_maxVirtualizationRoots)
&& (nullptr != s_virtualizationRoots[rootIndex].providerUserClient)
&& pid == s_virtualizationRoots[rootIndex].providerPid;
}
Expand All @@ -95,9 +93,16 @@ kern_return_t VirtualizationRoots_Init()
return KERN_FAILURE;
}

for (VirtualizationRootHandle i = 0; i < MaxVirtualizationRoots; ++i)
s_maxVirtualizationRoots = 128;
s_virtualizationRoots = Memory_AllocArray<VirtualizationRoot>(s_maxVirtualizationRoots);
if (nullptr == s_virtualizationRoots)
{
return KERN_RESOURCE_SHORTAGE;
}

for (VirtualizationRootHandle i = 0; i < s_maxVirtualizationRoots; ++i)
{
s_virtualizationRoots[i].index = i;
s_virtualizationRoots[i] = VirtualizationRoot{ };
}

return KERN_SUCCESS;
Expand All @@ -122,7 +127,7 @@ VirtualizationRootHandle VirtualizationRoot_FindForVnode(vnode_t vnode)
// Search up the tree until we hit a known virtualization root or THE root of the file system
while (rootIndex == RootHandle_None && NULLVP != vnode && !vnode_isvroot(vnode))
{
rootIndex = VirtualizationRoots_LookupVnode(vnode, nullptr);
rootIndex = VirtualizationRoots_FindRootAtVnode(vnode, nullptr);
if (rootIndex != RootHandle_None)
{
break;
Expand All @@ -141,7 +146,7 @@ VirtualizationRootHandle VirtualizationRoot_FindForVnode(vnode_t vnode)
return rootIndex;
}

VirtualizationRootHandle VirtualizationRoots_LookupVnode(vnode_t vnode, vfs_context_t context)
VirtualizationRootHandle VirtualizationRoots_FindRootAtVnode(vnode_t vnode, vfs_context_t context)
{
VnodeFsidInode fsidInode = Vnode_GetFsidAndInode(vnode, context);
uint32_t vid = vnode_vid(vnode);
Expand Down Expand Up @@ -190,7 +195,7 @@ VirtualizationRootHandle VirtualizationRoots_LookupVnode(vnode_t vnode, vfs_cont

static VirtualizationRootHandle FindUnusedIndex_Locked()
{
for (VirtualizationRootHandle i = 0; i < MaxVirtualizationRoots; ++i)
for (VirtualizationRootHandle i = 0; i < s_maxVirtualizationRoots; ++i)
{
if (!s_virtualizationRoots[i].inUse)
{
Expand All @@ -201,14 +206,45 @@ static VirtualizationRootHandle FindUnusedIndex_Locked()
return RootHandle_None;
}

static VirtualizationRootHandle FindUnusedIndexOrGrow_Locked()
{
VirtualizationRootHandle rootIndex = FindUnusedIndex_Locked();

if (RootHandle_None == rootIndex)
{
// No space, resize array
uint16_t newLength = MIN(s_maxVirtualizationRoots * 2u, INT16_MAX + 1u);
if (newLength <= s_maxVirtualizationRoots)
{
return RootHandle_None;
}

VirtualizationRoot* grownArray = Memory_AllocArray<VirtualizationRoot>(newLength);
uint32_t oldSizeBytes = sizeof(s_virtualizationRoots[0]) * s_maxVirtualizationRoots;
memcpy(grownArray, s_virtualizationRoots, oldSizeBytes);
Memory_Free(s_virtualizationRoots, oldSizeBytes);
s_virtualizationRoots = grownArray;

for (uint16_t i = s_maxVirtualizationRoots; i < newLength; ++i)
{
s_virtualizationRoots[i] = VirtualizationRoot{ };
}

rootIndex = s_maxVirtualizationRoots;
s_maxVirtualizationRoots = newLength;
}

return rootIndex;
}

static bool FsidsAreEqual(fsid_t a, fsid_t b)
{
return a.val[0] == b.val[0] && a.val[1] == b.val[1];
}

static VirtualizationRootHandle FindRootAtVnode_Locked(vnode_t vnode, uint32_t vid, VnodeFsidInode fileId)
{
for (VirtualizationRootHandle i = 0; i < MaxVirtualizationRoots; ++i)
for (VirtualizationRootHandle i = 0; i < s_maxVirtualizationRoots; ++i)
{
VirtualizationRoot& rootEntry = s_virtualizationRoots[i];
if (!rootEntry.inUse)
Expand Down Expand Up @@ -236,17 +272,16 @@ static VirtualizationRootHandle FindRootAtVnode_Locked(vnode_t vnode, uint32_t v
// Returns negative value if it failed, or inserted index on success
static VirtualizationRootHandle InsertVirtualizationRoot_Locked(PrjFSProviderUserClient* userClient, pid_t clientPID, vnode_t vnode, uint32_t vid, VnodeFsidInode persistentIds, const char* path)
{
VirtualizationRootHandle rootIndex = FindUnusedIndex_Locked();
VirtualizationRootHandle rootIndex = FindUnusedIndexOrGrow_Locked();

if (rootIndex >= 0)
if (RootHandle_None != rootIndex)
{
assert(rootIndex < MaxVirtualizationRoots);
assert(rootIndex < s_maxVirtualizationRoots);
VirtualizationRoot* root = &s_virtualizationRoots[rootIndex];

root->providerUserClient = userClient;
root->providerPid = clientPID;
root->inUse = true;
root->index = rootIndex;

root->rootVNode = vnode;
root->rootVNodeVid = vid;
Expand Down Expand Up @@ -314,7 +349,7 @@ VirtualizationRootResult VirtualizationRoot_RegisterProviderForPath(PrjFSProvide
rootIndex = InsertVirtualizationRoot_Locked(userClient, clientPID, virtualizationRootVNode, rootVid, vnodeIds, virtualizationRootPath);
if (rootIndex >= 0)
{
assert(rootIndex < MaxVirtualizationRoots);
assert(rootIndex < s_maxVirtualizationRoots);
VirtualizationRoot* root = &s_virtualizationRoots[rootIndex];

strlcpy(root->path, virtualizationRootPath, sizeof(root->path));
Expand Down Expand Up @@ -352,10 +387,10 @@ VirtualizationRootResult VirtualizationRoot_RegisterProviderForPath(PrjFSProvide
void ActiveProvider_Disconnect(VirtualizationRootHandle rootIndex)
{
assert(rootIndex >= 0);
assert(rootIndex <= MaxVirtualizationRoots);

RWLock_AcquireExclusive(s_rwLock);
{
assert(rootIndex <= s_maxVirtualizationRoots);

VirtualizationRoot* root = &s_virtualizationRoots[rootIndex];
assert(nullptr != root->providerUserClient);

Expand All @@ -371,19 +406,20 @@ void ActiveProvider_Disconnect(VirtualizationRootHandle rootIndex)
errno_t ActiveProvider_SendMessage(VirtualizationRootHandle rootIndex, const Message message)
{
assert(rootIndex >= 0);
assert(rootIndex < MaxVirtualizationRoots);

PrjFSProviderUserClient* userClient = nullptr;

RWLock_AcquireExclusive(s_rwLock);
RWLock_AcquireShared(s_rwLock);
{
assert(rootIndex < s_maxVirtualizationRoots);

userClient = s_virtualizationRoots[rootIndex].providerUserClient;
if (nullptr != userClient)
{
userClient->retain();
}
}
RWLock_ReleaseExclusive(s_rwLock);
RWLock_ReleaseShared(s_rwLock);

if (nullptr != userClient)
{
Expand Down Expand Up @@ -429,12 +465,12 @@ static const char* GetRelativePath(const char* path, const char* root)
const char* VirtualizationRoot_GetRootRelativePath(VirtualizationRootHandle rootIndex, const char* path)
{
assert(rootIndex >= 0);
assert(rootIndex <= MaxVirtualizationRoots);

const char* relativePath;

RWLock_AcquireShared(s_rwLock);
{
assert(rootIndex < s_maxVirtualizationRoots);
assert(s_virtualizationRoots[rootIndex].inUse);
relativePath = GetRelativePath(path, s_virtualizationRoots[rootIndex].path);
}
Expand Down
2 changes: 1 addition & 1 deletion ProjFS.Mac/PrjFSKext/PrjFSKext/VirtualizationRoots.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ bool VirtualizationRoot_PIDMatchesProvider(VirtualizationRootHandle rootHandle,
bool VirtualizationRoot_IsValidRootHandle(VirtualizationRootHandle rootHandle);
const char* VirtualizationRoot_GetRootRelativePath(VirtualizationRootHandle rootHandle, const char* path);

int16_t VirtualizationRoots_LookupVnode(vnode_t vnode, vfs_context_t context);
int16_t VirtualizationRoots_FindRootAtVnode(vnode_t vnode, vfs_context_t context);

0 comments on commit 867f547

Please sign in to comment.