]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.14.69/cap_inode_getsecurity-use-d_find_any_alias-instead-of-d_find_alias.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.14.69 / cap_inode_getsecurity-use-d_find_any_alias-instead-of-d_find_alias.patch
1 From 355139a8dba446cc11a424cddbf7afebc3041ba1 Mon Sep 17 00:00:00 2001
2 From: "Eddie.Horng" <eddie.horng@mediatek.com>
3 Date: Fri, 20 Jul 2018 15:30:00 +0800
4 Subject: cap_inode_getsecurity: use d_find_any_alias() instead of d_find_alias()
5
6 From: Eddie.Horng <eddie.horng@mediatek.com>
7
8 commit 355139a8dba446cc11a424cddbf7afebc3041ba1 upstream.
9
10 The code in cap_inode_getsecurity(), introduced by commit 8db6c34f1dbc
11 ("Introduce v3 namespaced file capabilities"), should use
12 d_find_any_alias() instead of d_find_alias() do handle unhashed dentry
13 correctly. This is needed, for example, if execveat() is called with an
14 open but unlinked overlayfs file, because overlayfs unhashes dentry on
15 unlink.
16 This is a regression of real life application, first reported at
17 https://www.spinics.net/lists/linux-unionfs/msg05363.html
18
19 Below reproducer and setup can reproduce the case.
20 const char* exec="echo";
21 const char *newargv[] = { "echo", "hello", NULL};
22 const char *newenviron[] = { NULL };
23 int fd, err;
24
25 fd = open(exec, O_PATH);
26 unlink(exec);
27 err = syscall(322/*SYS_execveat*/, fd, "", newargv, newenviron,
28 AT_EMPTY_PATH);
29 if(err<0)
30 fprintf(stderr, "execveat: %s\n", strerror(errno));
31
32 gcc compile into ~/test/a.out
33 mount -t overlay -orw,lowerdir=/mnt/l,upperdir=/mnt/u,workdir=/mnt/w
34 none /mnt/m
35 cd /mnt/m
36 cp /bin/echo .
37 ~/test/a.out
38
39 Expected result:
40 hello
41 Actually result:
42 execveat: Invalid argument
43 dmesg:
44 Invalid argument reading file caps for /dev/fd/3
45
46 The 2nd reproducer and setup emulates similar case but for
47 regular filesystem:
48 const char* exec="echo";
49 int fd, err;
50 char buf[256];
51
52 fd = open(exec, O_RDONLY);
53 unlink(exec);
54 err = fgetxattr(fd, "security.capability", buf, 256);
55 if(err<0)
56 fprintf(stderr, "fgetxattr: %s\n", strerror(errno));
57
58 gcc compile into ~/test_fgetxattr
59
60 cd /tmp
61 cp /bin/echo .
62 ~/test_fgetxattr
63
64 Result:
65 fgetxattr: Invalid argument
66
67 On regular filesystem, for example, ext4 read xattr from
68 disk and return to execveat(), will not trigger this issue, however,
69 the overlay attr handler pass real dentry to vfs_getxattr() will.
70 This reproducer calls fgetxattr() with an unlinked fd, involkes
71 vfs_getxattr() then reproduced the case that d_find_alias() in
72 cap_inode_getsecurity() can't find the unlinked dentry.
73
74 Suggested-by: Amir Goldstein <amir73il@gmail.com>
75 Acked-by: Amir Goldstein <amir73il@gmail.com>
76 Acked-by: Serge E. Hallyn <serge@hallyn.com>
77 Fixes: 8db6c34f1dbc ("Introduce v3 namespaced file capabilities")
78 Cc: <stable@vger.kernel.org> # v4.14
79 Signed-off-by: Eddie Horng <eddie.horng@mediatek.com>
80 Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
81 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
82
83 ---
84 security/commoncap.c | 2 +-
85 1 file changed, 1 insertion(+), 1 deletion(-)
86
87 --- a/security/commoncap.c
88 +++ b/security/commoncap.c
89 @@ -388,7 +388,7 @@ int cap_inode_getsecurity(struct inode *
90 if (strcmp(name, "capability") != 0)
91 return -EOPNOTSUPP;
92
93 - dentry = d_find_alias(inode);
94 + dentry = d_find_any_alias(inode);
95 if (!dentry)
96 return -EINVAL;
97