Access control in Assise
Hi,
We're working on implementing access control using Assise leases. We have a proposed methodology, but have a few questions about the code.
Before presenting the questions, here's our current proposed methodology:
- Each LibFS registers with a SharedFS upon initialization. We would add an extra step where the LibFS shares its owner and the owner's primary group with the local SharedFS.
- The local SharedFS would track these values in a map (PID to owner and group).
- The map could be backed up to a private file for crash consistency.
- Any LibFS requests must first go through the local SharedFS, so if we need to forward this information to another SharedFS, any forwarded requests would also include this owner + group information.
- The SharedFS holding the requested file/directory will make the lease decision. Three new fields in the inode,
uid,gid, andperms, will be added.-
uidandgidmatch the process's class (user, group, other). - The type of lease (read/write) will determine which set of permissions in
permsto check against.
-
- If the lease is granted, it will behave identically to current Assise, regardless of whether the permissions of the file/directory change.
- If a process maliciously writes to its log when it's denied permissions (or has no lease in general), digesting those log entries should fail because the process didn't have the lease at that time.
Here's our questions:
- Do we also need to implement execute permissions?
- Read leases don't seem to be implemented in KernFS's
modify_lease_statefunction.- Do we need to implement these?
- Could we instead just do a naive check and return something like
-EACCESif the permissions check doesn't work out?
-
acquire_leaseis commented out innamex, which is presumably where Assise goes to acquire leases.- Is this supposed to be left commented out?
- If so, where does LibFS guide POSIX calls to acquire read/write leases?
- We propose to have SharedFSes track the owner / the owner's primary group of each local LibFS.
- We can't find any existing data structure in libfs/src/mkfs/mfks.c or kernfs/fs.c that explicitly sets up relationships between LibFSes and KernFSes.
- Can we assume that these relationships are registered statically?
- If so, how can we send process owner + group information to SharedFSes when a LibFS starts up? Is this a secure procedure, or should we assume processes can lie about their owner?
- Should there be any changes to the digestion of logs?
- If our permission checks are correct, and digestion rejects writes from processes that lack(ed) the write leases at the time of their writes, then the answer should be no.
- Are there any edge cases where lease history is unused for checking the validity of log writes?
- How can we run libfs as a non-privileged user?
- For example, running
./run.sh iotest sw 2G 4K 1(nosudo) yields the following error. It looks like something in the shim requires extra privileges. - Would it be okay to spoof LibFS owners / groups in our tests, if this is something we can't avoid?
- For example, running
dev-dax engine is initialized: dev_path /dev/dax0.0 size 4096 MB
fetching node's IP address..
Process pid is 19681
ip address on interface 'lo' is 127.0.0.1
cluster settings:
--- node 0 - ip:127.0.0.1
Connecting to KernFS instance 0 [ip: 127.0.0.1]
[Local-Client] Creating connection (pid:19681, app_type:0, status:pending) to 127.0.0.1:12345 on sockfd 0
[Local-Client] Creating connection (pid:19681, app_type:1, status:pending) to 127.0.0.1:12345 on sockfd 1
[Local-Client] Creating connection (pid:19681, app_type:2, status:pending) to 127.0.0.1:12345 on sockfd 2
In thread
In thread
In thread
SEND --> MSG_INIT [pid 0|19681]
RECV <-- MSG_SHM [paths: /shm_recv_0|/shm_send_0]
shm_open failed.
: Permission denied
- When running the lease test, e.g.
sudo ./run.sh lease_test c 1 1, we cannot run the test as we get an error, for example:incorrect fd -2: file /mlfs/fileset/f0_7618.- Other tests, like many_files_test, work fine.
- We see similar errors when running
sudo ./run_lease_test_example.shin the output logs. What can we do to solve this?
Thanks for your help!
I'm cc'ing Waleed to answer a few of your questions.
On Wed, Nov 17, 2021 at 3:11 PM Carson Molder @.***> wrote:
Hi,
We're working on implementing access control using Assise leases. We have a proposed methodology, but have a few questions about the code.
Before presenting the questions, here's our current proposed methodology:
- Each LibFS registers with a SharedFS upon initialization. We would add an extra step where the LibFS shares its owner and the owner's primary group with the local SharedFS.
- The local SharedFS would track these values in a map (PID to owner and group).
A likely simpler way is to just parse /proc/
- The map could be backed up to a private file for crash consistency.
No need. That should be covered by the leases. If a process has the lease, that confers its right to access the file.
- Any LibFS requests must first go through the local SharedFS, so if we need to forward this information to another SharedFS, any forwarded requests would also include this owner + group information.
Not sure you'll ever need to forward it. Once you obtained the lease in the local sharedfs, you should be able to simply check permissions on behalf of the requesting libfs and only grant the lease to the libfs if access is granted.
- The SharedFS holding the requested file/directory will make the lease decision. Three new fields in the inode, uid, gid, and perms, will be added.
- uid and gid match the process's class (user, group, other).
- The type of lease (read/write) will determine which set of permissions in perms to check against.
I assume perms represents the user/group/other rwx rights? In that case, this seems right. Are these fields not already stored in the inode?
- If the lease is granted, it will behave identically to current Assise, regardless of whether the permissions of the file/directory change.
- If a process maliciously writes to its log when it's denied permissions (or has no lease in general), digesting those log entries should fail because the process didn't have the lease at that time.
That's correct, AFAIK. POSIX mandates that once rights to a file/directory have been granted and the file/directory is open, you continue holding the right until you close the file/directory.
There is a potential corner case here that if a lease is temporarily given up, but the file is still open, the lease should be re-granted even if permissions changed, as it is the open file descriptor that mandates continued access.
Here's our questions:
- Do we also need to implement execute permissions?
Read/write is more important. I'd work on that first. Execute would likely be handled through a special execve call to the sharedfs.
- Read leases don't seem to be implemented https://github.com/ut-osa/assise/blob/8dca2f944241b12f2b7f482ce0bf00dc486631a1/libfs/src/experimental/leases.c#L724 in KernFS's modify_lease_state function.
- Do we need to implement these?
- Could we instead just do a naive check and return something like -EACCES if the permissions check doesn't work out?
Just doing the check isn't enough. You also need to prevent the process from reading the file by disallowing mapping the file into its virtual memory. The read lease implementation is secondary to that. The leases in this case simply control consistency, rather than convey access permission.
- acquire_lease is commented out https://github.com/ut-osa/assise/blob/master/libfs/src/filesystem/dirent.c#L302 in namex, which is presumably where Assise goes to acquire leases.
- Is this supposed to be left commented out?
- If so, where does LibFS guide POSIX calls to acquire read/write leases?
Waleed (cc'ed) should be able to answer this.
- We propose to have SharedFSes track the owner / the owner's primary group of each local LibFS.
- We can't find any existing data structure in libfs/src/mkfs/mfks.c https://github.com/ut-osa/assise/blob/master/libfs/src/mkfs/mkfs.c or kernfs/fs.c https://github.com/ut-osa/assise/blob/master/kernfs/fs.c that explicitly sets up relationships between LibFSes and KernFSes.
- Can we assume that these relationships are registered statically?
- If so, how can we send process owner + group information to SharedFSes when a LibFS starts up? Is this a secure procedure, or should we assume processes can lie about their owner?
See above answer.
- Should there be any changes to the digestion of logs?
- If our permission checks are correct, and digestion rejects writes from processes that lack(ed) the write leases at the time of their writes, then the answer should be no.
- Are there any edge cases where lease history is unused for checking the validity of log writes?
The write leases should be enough to ensure the integrity of the update logs.
- How can we run libfs as a non-privileged user?
- For example, running ./run.sh iotest sw 2G 4K 1 (no sudo) yields the following error. It looks like something in the shim requires extra privileges.
- Would it be okay to spoof LibFS owners / groups in our tests, if this is something we can't avoid?
It seems that the shared memory that is mapped by libfs (presumably for update logs and potentially to map the read-shared area) don't have the proper permissions. You should implement the proper permissions so you can run non-root processes. Spoofing owners/groups should only be a last resort in case a proper implementation has too many obstacles (in which case, you should explain what they are in your report).
dev-dax engine is initialized: dev_path /dev/dax0.0 size 4096 MB fetching node's IP address.. Process pid is 19681 ip address on interface 'lo' is 127.0.0.1 cluster settings: --- node 0 - ip:127.0.0.1 Connecting to KernFS instance 0 [ip: 127.0.0.1] [Local-Client] Creating connection (pid:19681, app_type:0, status:pending) to 127.0.0.1:12345 on sockfd 0 [Local-Client] Creating connection (pid:19681, app_type:1, status:pending) to 127.0.0.1:12345 on sockfd 1 [Local-Client] Creating connection (pid:19681, app_type:2, status:pending) to 127.0.0.1:12345 on sockfd 2 In thread In thread In thread SEND --> MSG_INIT [pid 0|19681] RECV <-- MSG_SHM [paths: /shm_recv_0|/shm_send_0] shm_open failed. : Permission denied
- When running the lease test, e.g. sudo ./run.sh lease_test c 1 1, we cannot run the test as we get an error, for example: incorrect fd -2: file /mlfs/fileset/f0_7618.
- Other tests, like many_files_test, work fine.
- We see similar errors when running sudo ./run_lease_test_example.sh in the output logs. What can we do to solve this?
Waleed should be able to answer this question.
-- Simon
acquire_lease is commented out in namex, which is presumably where Assise goes to acquire leases. Is this supposed to be left commented out? If so, where does LibFS guide POSIX calls to acquire read/write leases?
Write leases are acquired at src/filesystem/file.c in 'mlfs_object_create()'. The lines you found are specifically for read leases, and are commented temporarily. They will be re-enabled in the future once I get a chance to properly test them.
How can we run libfs as a non-privileged user? For example, running ./run.sh iotest sw 2G 4K 1 (no sudo) yields the following error. It looks like something in the shim requires extra privileges. Would it be okay to spoof LibFS owners / groups in our tests, if this is something we can't avoid?
The permissions issue you're encountering is indeed related to the shm files, which are created at this line. One quick workaround is to change the permissions of these files manually. On ubuntu, running sudo chmod 777 /dev/shm/shm_* should do the trick. I'll see if I can introduce a proper patch for this in the future.
When running the lease test, e.g. sudo ./run.sh lease_test c 1 1, we cannot run the test as we get an error, for example: incorrect fd -2: file /mlfs/fileset/f0_7618. Other tests, like many_files_test, work fine. We see similar errors when running sudo ./run_lease_test_example.sh in the output logs. What can we do to solve this?
I have pushed a hotfix for the 'lease_test' benchmark. It should run to completion now.