diff options
Diffstat (limited to 'recipes-kernel/linux/linux-hierofalcon-4.1/vfs-CVE-2015-2925.patch')
-rw-r--r-- | recipes-kernel/linux/linux-hierofalcon-4.1/vfs-CVE-2015-2925.patch | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-hierofalcon-4.1/vfs-CVE-2015-2925.patch b/recipes-kernel/linux/linux-hierofalcon-4.1/vfs-CVE-2015-2925.patch new file mode 100644 index 0000000..aa20d7f --- /dev/null +++ b/recipes-kernel/linux/linux-hierofalcon-4.1/vfs-CVE-2015-2925.patch | |||
@@ -0,0 +1,126 @@ | |||
1 | From eed13ce27f481cba65352e73403ca15e67bc26a4 Mon Sep 17 00:00:00 2001 | ||
2 | From: "Eric W. Biederman" <ebiederm@xmission.com> | ||
3 | Date: Sat, 15 Aug 2015 20:27:13 -0500 | ||
4 | Subject: vfs: Test for and handle paths that are unreachable from their | ||
5 | mnt_root | ||
6 | |||
7 | commit 397d425dc26da728396e66d392d5dcb8dac30c37 upstream. | ||
8 | |||
9 | In rare cases a directory can be renamed out from under a bind mount. | ||
10 | In those cases without special handling it becomes possible to walk up | ||
11 | the directory tree to the root dentry of the filesystem and down | ||
12 | from the root dentry to every other file or directory on the filesystem. | ||
13 | |||
14 | Like division by zero .. from an unconnected path can not be given | ||
15 | a useful semantic as there is no predicting at which path component | ||
16 | the code will realize it is unconnected. We certainly can not match | ||
17 | the current behavior as the current behavior is a security hole. | ||
18 | |||
19 | Therefore when encounting .. when following an unconnected path | ||
20 | return -ENOENT. | ||
21 | |||
22 | - Add a function path_connected to verify path->dentry is reachable | ||
23 | from path->mnt.mnt_root. AKA to validate that rename did not do | ||
24 | something nasty to the bind mount. | ||
25 | |||
26 | To avoid races path_connected must be called after following a path | ||
27 | component to it's next path component. | ||
28 | |||
29 | Fixes CVE-2015-2925. | ||
30 | Upstream-Status: Backport | ||
31 | |||
32 | Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com> | ||
33 | Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> | ||
34 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | ||
35 | Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> | ||
36 | --- | ||
37 | fs/namei.c | 31 ++++++++++++++++++++++++++++--- | ||
38 | 1 file changed, 28 insertions(+), 3 deletions(-) | ||
39 | |||
40 | diff --git a/fs/namei.c b/fs/namei.c | ||
41 | index fe30d3b..acdab61 100644 | ||
42 | --- a/fs/namei.c | ||
43 | +++ b/fs/namei.c | ||
44 | @@ -505,6 +505,24 @@ struct nameidata { | ||
45 | char *saved_names[MAX_NESTED_LINKS + 1]; | ||
46 | }; | ||
47 | |||
48 | +/** | ||
49 | + * path_connected - Verify that a path->dentry is below path->mnt.mnt_root | ||
50 | + * @path: nameidate to verify | ||
51 | + * | ||
52 | + * Rename can sometimes move a file or directory outside of a bind | ||
53 | + * mount, path_connected allows those cases to be detected. | ||
54 | + */ | ||
55 | +static bool path_connected(const struct path *path) | ||
56 | +{ | ||
57 | + struct vfsmount *mnt = path->mnt; | ||
58 | + | ||
59 | + /* Only bind mounts can have disconnected paths */ | ||
60 | + if (mnt->mnt_root == mnt->mnt_sb->s_root) | ||
61 | + return true; | ||
62 | + | ||
63 | + return is_subdir(path->dentry, mnt->mnt_root); | ||
64 | +} | ||
65 | + | ||
66 | /* | ||
67 | * Path walking has 2 modes, rcu-walk and ref-walk (see | ||
68 | * Documentation/filesystems/path-lookup.txt). In situations when we can't | ||
69 | @@ -1194,6 +1212,8 @@ static int follow_dotdot_rcu(struct nameidata *nd) | ||
70 | goto failed; | ||
71 | nd->path.dentry = parent; | ||
72 | nd->seq = seq; | ||
73 | + if (unlikely(!path_connected(&nd->path))) | ||
74 | + goto failed; | ||
75 | break; | ||
76 | } | ||
77 | if (!follow_up_rcu(&nd->path)) | ||
78 | @@ -1290,7 +1310,7 @@ static void follow_mount(struct path *path) | ||
79 | } | ||
80 | } | ||
81 | |||
82 | -static void follow_dotdot(struct nameidata *nd) | ||
83 | +static int follow_dotdot(struct nameidata *nd) | ||
84 | { | ||
85 | if (!nd->root.mnt) | ||
86 | set_root(nd); | ||
87 | @@ -1306,6 +1326,10 @@ static void follow_dotdot(struct nameidata *nd) | ||
88 | /* rare case of legitimate dget_parent()... */ | ||
89 | nd->path.dentry = dget_parent(nd->path.dentry); | ||
90 | dput(old); | ||
91 | + if (unlikely(!path_connected(&nd->path))) { | ||
92 | + path_put(&nd->path); | ||
93 | + return -ENOENT; | ||
94 | + } | ||
95 | break; | ||
96 | } | ||
97 | if (!follow_up(&nd->path)) | ||
98 | @@ -1313,6 +1337,7 @@ static void follow_dotdot(struct nameidata *nd) | ||
99 | } | ||
100 | follow_mount(&nd->path); | ||
101 | nd->inode = nd->path.dentry->d_inode; | ||
102 | + return 0; | ||
103 | } | ||
104 | |||
105 | /* | ||
106 | @@ -1541,7 +1566,7 @@ static inline int handle_dots(struct nameidata *nd, int type) | ||
107 | if (follow_dotdot_rcu(nd)) | ||
108 | return -ECHILD; | ||
109 | } else | ||
110 | - follow_dotdot(nd); | ||
111 | + return follow_dotdot(nd); | ||
112 | } | ||
113 | return 0; | ||
114 | } | ||
115 | @@ -2290,7 +2315,7 @@ mountpoint_last(struct nameidata *nd, struct path *path) | ||
116 | if (unlikely(nd->last_type != LAST_NORM)) { | ||
117 | error = handle_dots(nd, nd->last_type); | ||
118 | if (error) | ||
119 | - goto out; | ||
120 | + return error; | ||
121 | dentry = dget(nd->path.dentry); | ||
122 | goto done; | ||
123 | } | ||
124 | -- | ||
125 | cgit v0.12 | ||
126 | |||