summaryrefslogtreecommitdiff
path: root/security/commoncap.c
diff options
context:
space:
mode:
authorEddie.Horng <eddie.horng@mediatek.com>2018-07-20 10:30:00 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-09-09 20:56:01 +0300
commit5a842ecca279f583c3fdc9a1ed8fe7a4cc348789 (patch)
tree067dfbedbb53b05a84e67492bcb729236d562081 /security/commoncap.c
parentd1a265da7b2983e3201988f1a8202e749e2d4352 (diff)
downloadlinux-5a842ecca279f583c3fdc9a1ed8fe7a4cc348789.tar.xz
cap_inode_getsecurity: use d_find_any_alias() instead of d_find_alias()
commit 355139a8dba446cc11a424cddbf7afebc3041ba1 upstream. The code in cap_inode_getsecurity(), introduced by commit 8db6c34f1dbc ("Introduce v3 namespaced file capabilities"), should use d_find_any_alias() instead of d_find_alias() do handle unhashed dentry correctly. This is needed, for example, if execveat() is called with an open but unlinked overlayfs file, because overlayfs unhashes dentry on unlink. This is a regression of real life application, first reported at https://www.spinics.net/lists/linux-unionfs/msg05363.html Below reproducer and setup can reproduce the case. const char* exec="echo"; const char *newargv[] = { "echo", "hello", NULL}; const char *newenviron[] = { NULL }; int fd, err; fd = open(exec, O_PATH); unlink(exec); err = syscall(322/*SYS_execveat*/, fd, "", newargv, newenviron, AT_EMPTY_PATH); if(err<0) fprintf(stderr, "execveat: %s\n", strerror(errno)); gcc compile into ~/test/a.out mount -t overlay -orw,lowerdir=/mnt/l,upperdir=/mnt/u,workdir=/mnt/w none /mnt/m cd /mnt/m cp /bin/echo . ~/test/a.out Expected result: hello Actually result: execveat: Invalid argument dmesg: Invalid argument reading file caps for /dev/fd/3 The 2nd reproducer and setup emulates similar case but for regular filesystem: const char* exec="echo"; int fd, err; char buf[256]; fd = open(exec, O_RDONLY); unlink(exec); err = fgetxattr(fd, "security.capability", buf, 256); if(err<0) fprintf(stderr, "fgetxattr: %s\n", strerror(errno)); gcc compile into ~/test_fgetxattr cd /tmp cp /bin/echo . ~/test_fgetxattr Result: fgetxattr: Invalid argument On regular filesystem, for example, ext4 read xattr from disk and return to execveat(), will not trigger this issue, however, the overlay attr handler pass real dentry to vfs_getxattr() will. This reproducer calls fgetxattr() with an unlinked fd, involkes vfs_getxattr() then reproduced the case that d_find_alias() in cap_inode_getsecurity() can't find the unlinked dentry. Suggested-by: Amir Goldstein <amir73il@gmail.com> Acked-by: Amir Goldstein <amir73il@gmail.com> Acked-by: Serge E. Hallyn <serge@hallyn.com> Fixes: 8db6c34f1dbc ("Introduce v3 namespaced file capabilities") Cc: <stable@vger.kernel.org> # v4.14 Signed-off-by: Eddie Horng <eddie.horng@mediatek.com> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'security/commoncap.c')
-rw-r--r--security/commoncap.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/security/commoncap.c b/security/commoncap.c
index 1c1f64582bb5..ae26ef006988 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -388,7 +388,7 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
if (strcmp(name, "capability") != 0)
return -EOPNOTSUPP;
- dentry = d_find_alias(inode);
+ dentry = d_find_any_alias(inode);
if (!dentry)
return -EINVAL;