| From: David Howells <dhowells@redhat.com> |
| Date: Wed, 16 May 2018 21:25:46 +0100 |
| Subject: afs: Fix directory permissions check |
| |
| commit 378831e4daec75fbba6d3612bcf3b4dd00ddbf08 upstream. |
| |
| Doing faccessat("/afs/some/directory", 0) triggers a BUG in the permissions |
| check code. |
| |
| Fix this by just removing the BUG section. If no permissions are asked |
| for, just return okay if the file exists. |
| |
| Also: |
| |
| (1) Split up the directory check so that it has separate if-statements |
| rather than if-else-if (e.g. checking for MAY_EXEC shouldn't skip the |
| check for MAY_READ and MAY_WRITE). |
| |
| (2) Check for MAY_CHDIR as MAY_EXEC. |
| |
| Without the main fix, the following BUG may occur: |
| |
| kernel BUG at fs/afs/security.c:386! |
| invalid opcode: 0000 [#1] SMP PTI |
| ... |
| RIP: 0010:afs_permission+0x19d/0x1a0 [kafs] |
| ... |
| Call Trace: |
| ? inode_permission+0xbe/0x180 |
| ? do_faccessat+0xdc/0x270 |
| ? do_syscall_64+0x60/0x1f0 |
| ? entry_SYSCALL_64_after_hwframe+0x49/0xbe |
| |
| Fixes: 00d3b7a4533e ("[AFS]: Add security support.") |
| Reported-by: Jonathan Billings <jsbillings@jsbillings.org> |
| Signed-off-by: David Howells <dhowells@redhat.com> |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| fs/afs/security.c | 10 +++------- |
| 1 file changed, 3 insertions(+), 7 deletions(-) |
| |
| --- a/fs/afs/security.c |
| +++ b/fs/afs/security.c |
| @@ -323,18 +323,14 @@ int afs_permission(struct inode *inode, |
| mask, access, S_ISDIR(inode->i_mode) ? "dir" : "file"); |
| |
| if (S_ISDIR(inode->i_mode)) { |
| - if (mask & MAY_EXEC) { |
| + if (mask & (MAY_EXEC | MAY_READ | MAY_CHDIR)) { |
| if (!(access & AFS_ACE_LOOKUP)) |
| goto permission_denied; |
| - } else if (mask & MAY_READ) { |
| - if (!(access & AFS_ACE_LOOKUP)) |
| - goto permission_denied; |
| - } else if (mask & MAY_WRITE) { |
| + } |
| + if (mask & MAY_WRITE) { |
| if (!(access & (AFS_ACE_DELETE | /* rmdir, unlink, rename from */ |
| AFS_ACE_INSERT))) /* create, mkdir, symlink, rename to */ |
| goto permission_denied; |
| - } else { |
| - BUG(); |
| } |
| } else { |
| if (!(access & AFS_ACE_LOOKUP)) |