OneFS: Linux kernel update to NFS causes `access` call failures
Summary: An update to Network File System (NFS) code in the Linux kernel has changed the behavior of `access` calls checking `WRITE` permissions on for specific OneFS permission sets. This change brings the Linux NFS and Server Message Block (SMB) behaviors in line with one another, making this check consistent regardless of what protocol you are using. ...
Symptoms
After a Linux kernel upgrade access checks that had previously succeeded now fail on directories in which the accessing user does not have "delete_child" permissions on a directory involved with their workflow. This can be validated using the Linux test command with the -w flag against that same directory; on old kernel versions, the return code from that command is 0 whereas in newer kernels it is 1.
This impacts Red Hat and Centos clients moving from version 7 to newer releases.
Cause
This change in behavior was introduced in Linux mainline kernel v4.13-rc2 during a refactor of the NFS driver code. However apparently the check was present as of mainline kernel v3.7-rc1
, and was not being correctly called.
After extensive review, we believe that both the new Linux kernel behavior and our behavior are correct. The linux test command and access system calls are both based on the POSIX standard, which only conceptualizes:
- READ
- WRITE
- EXECUTE
Whereas per rfc1813#section-3.3.4 and rfc7530#section-16.1
; NFS allows more granular permissions, and therefore conceptualizes:
- READ
- MODIFY
- APPEND
- DELETE
- EXECUTE
With the DELETE permission being defined as whether a client can Delete an existing directory entry. This directly maps to delete_child in OneFS, and should be denied in circumstances where the client does not have that permission. Also notice; POSIX and NFS permissions do not exactly match up. POSIX WRITE includes all the concepts in the separate NFS MODIFY, APPEND, and DELETE permissions. So when a POSIX tool attempts to check "WRITE" permissions, the linux kernel is translating that request for "WRITE" into "MODIFY and APPEND and DELETE"
Finally, the newer behavior is more in line with other Linux file system drivers that also support this permission set. For example, testing against an SMB filer with the same permission set also returns a failure when checking POSIX WRITE with the test command using the -w flag.
# Old kernel ancons@ubuntu:~$ uname -r 4.13.0-041300rc1-generic ancons@ubuntu:~$ sudo mount -o vers=4,proto=tcp 10.20.0.181:/ifs /mnt/nfs ancons@ubuntu:~$ sudo mount -o user=admin,pass=a //10.20.0.181/ifs /mnt/smb ancons@ubuntu:~$ test -w /mnt/nfs/posix; echo "$?" 0 ancons@ubuntu:~$ test -w /mnt/smb/posix; echo "$?" 1 # New kernel ancons@ubuntu:~$ uname -r 4.14.0-041400rc4-generic ancons@ubuntu:~$ sudo mount -o vers=4,proto=tcp 10.20.0.181:/ifs /mnt/nfs ancons@ubuntu:~$ sudo mount -o user=admin,pass=a //10.20.0.181/ifs /mnt/smb ancons@ubuntu:~$ test -w /mnt/nfs/posix; echo "$?" 1 ancons@ubuntu:~$ test -w /mnt/smb/posix; echo "$?" 1
Resolution
Both the OneFS and Linux behaviors in this circumstance are correct, as such workflows impacted by this issue must provide the delete_child permission to impacted users and groups. For example, if a directory provides full access to its owner user and group, but removes delete_child from the everyone permission, they can either add that permission to everyone, or they can add an additional Access Control Entry (ACE) for the user or group that is seeing issues to the Access Control List (ACL) of the directly.
# ACL that only allows root to delete child items p980-1-1# ls -led /ifs/posix-delete_child drwxrwxrwx + 2 root wheel 0 Jun 18 14:20 /ifs/posix-delete_child OWNER: user:root GROUP: group:wheel 0: user:root allow dir_gen_read,dir_gen_write,dir_gen_execute,std_write_dac,delete_child 1: group:wheel allow dir_gen_read,dir_gen_write,dir_gen_execute,delete_child 2: everyone allow dir_gen_read,dir_gen_write,dir_gen_execute # ACL that allows a specific additional group to delete child items p980-1-1# ls -led /ifs/posix-delete_child drwxrwxrwx + 2 root wheel 0 Jun 18 14:20 /ifs/posix-delete_child OWNER: user:root GROUP: group:wheel 0: group:admin allow dir_gen_read,dir_gen_write,dir_gen_execute,delete_child 1: user:root allow dir_gen_read,dir_gen_write,dir_gen_execute,std_write_dac,delete_child 2: group:wheel allow dir_gen_read,dir_gen_write,dir_gen_execute,delete_child 3: everyone allow dir_gen_read,dir_gen_write,dir_gen_execute # ACL that allows everyone to delete child items p980-1-1# ls -led /ifs/posix-delete_child drwxrwxrwx + 2 root wheel 0 Jun 18 14:20 /ifs/posix-delete_child OWNER: user:root GROUP: group:wheel 0: user:root allow dir_gen_read,dir_gen_write,dir_gen_execute,std_write_dac,delete_child 1: group:wheel allow dir_gen_read,dir_gen_write,dir_gen_execute,delete_child 2: everyone allow dir_gen_read,dir_gen_write,dir_gen_execute,delete_child
It is also possible to update the Linux kernel to revert the behavior. This requires building the Linux kernel from source after updating fs/nfs/dir.c to remove the NFS4_ACCESS_DELETE requirement from the NFS_MAY_WRITE macro.
Before:
#define NFS_MAY_WRITE (NFS4_ACCESS_MODIFY | \ NFS4_ACCESS_EXTEND | \ NFS4_ACCESS_DELETE)
After:
#define NFS_MAY_WRITE (NFS4_ACCESS_MODIFY | \ NFS4_ACCESS_EXTEND)