diff options
author | George McCollister <george.mccollister@gmail.com> | 2019-02-25 10:37:07 -0600 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2019-03-24 16:49:54 +0000 |
commit | 0e63d91b2b6c8a9afaec1988d8845643e3787af0 (patch) | |
tree | 76d7c18561e3947969f94334ff219b09baacf746 /meta/recipes-core | |
parent | d5400f11dd1f8f5f7ad29faaabda80185270fe5b (diff) | |
download | poky-0e63d91b2b6c8a9afaec1988d8845643e3787af0.tar.gz |
systemd: fix CVE-2018-15687
Backport patch to fix the following CVE.
CVE: CVE-2018-15687
Based on thud commit eeb621aa19f690971caf862290a172a115578ba1
The patch in the thud commit doesn't compile against 237. Use the
version of this patch, CVE-2018-15687.patch from
systemd_237-3ubuntu10.13.debian.
(From OE-Core rev: 3e8ba9af58253ed9db0f0376a8e2966e45ee089e)
Signed-off-by: George McCollister <george.mccollister@gmail.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/recipes-core')
-rw-r--r-- | meta/recipes-core/systemd/systemd/0001-chown-recursive-let-s-rework-the-recursive-logic-to-.patch | 252 | ||||
-rw-r--r-- | meta/recipes-core/systemd/systemd_237.bb | 1 |
2 files changed, 253 insertions, 0 deletions
diff --git a/meta/recipes-core/systemd/systemd/0001-chown-recursive-let-s-rework-the-recursive-logic-to-.patch b/meta/recipes-core/systemd/systemd/0001-chown-recursive-let-s-rework-the-recursive-logic-to-.patch new file mode 100644 index 0000000000..9a0b55f97d --- /dev/null +++ b/meta/recipes-core/systemd/systemd/0001-chown-recursive-let-s-rework-the-recursive-logic-to-.patch | |||
@@ -0,0 +1,252 @@ | |||
1 | From 2da8ba3f507345d0401ea9d7191fa16ffa560ebc Mon Sep 17 00:00:00 2001 | ||
2 | From: Lennart Poettering <lennart@poettering.net> | ||
3 | Date: Fri, 19 Oct 2018 11:26:59 +0200 | ||
4 | Subject: [PATCH] chown-recursive: let's rework the recursive logic to use | ||
5 | O_PATH | ||
6 | |||
7 | That way we can pin a specific inode and analyze it and manipulate it | ||
8 | without it being swapped out beneath our hands. | ||
9 | |||
10 | Fixes a vulnerability originally found by Jann Horn from Google. | ||
11 | |||
12 | CVE-2018-15687 | ||
13 | LP: #1796692 | ||
14 | https://bugzilla.redhat.com/show_bug.cgi?id=1639076 | ||
15 | |||
16 | Origin: upstream, https://github.com/poettering/systemd/commit/5de6cce58b3e8b79239b6e83653459d91af6e57c | ||
17 | Bug-Ubuntu: https://launchpad.net/bugs/1796692 | ||
18 | |||
19 | Patch for 237 from: | ||
20 | systemd_237-3ubuntu10.13.debian CVE-2018-15687.patch | ||
21 | |||
22 | CVE: CVE-2018-15687 | ||
23 | Upstream-Status: Backport | ||
24 | |||
25 | --- | ||
26 | src/core/chown-recursive.c | 146 ++++++++++++++++++++++----------------------- | ||
27 | 1 file changed, 70 insertions(+), 76 deletions(-) | ||
28 | |||
29 | diff --git a/src/core/chown-recursive.c b/src/core/chown-recursive.c | ||
30 | index c479450..27c6448 100644 | ||
31 | --- a/src/core/chown-recursive.c | ||
32 | +++ b/src/core/chown-recursive.c | ||
33 | @@ -18,18 +18,20 @@ | ||
34 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | ||
35 | ***/ | ||
36 | |||
37 | -#include <sys/types.h> | ||
38 | -#include <sys/stat.h> | ||
39 | #include <fcntl.h> | ||
40 | +#include <sys/stat.h> | ||
41 | +#include <sys/types.h> | ||
42 | |||
43 | -#include "user-util.h" | ||
44 | -#include "macro.h" | ||
45 | -#include "fd-util.h" | ||
46 | -#include "dirent-util.h" | ||
47 | #include "chown-recursive.h" | ||
48 | +#include "dirent-util.h" | ||
49 | +#include "fd-util.h" | ||
50 | +#include "macro.h" | ||
51 | +#include "stdio-util.h" | ||
52 | +#include "strv.h" | ||
53 | +#include "user-util.h" | ||
54 | |||
55 | -static int chown_one(int fd, const char *name, const struct stat *st, uid_t uid, gid_t gid) { | ||
56 | - int r; | ||
57 | +static int chown_one(int fd, const struct stat *st, uid_t uid, gid_t gid) { | ||
58 | + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1]; | ||
59 | |||
60 | assert(fd >= 0); | ||
61 | assert(st); | ||
62 | @@ -38,90 +40,82 @@ | ||
63 | (!gid_is_valid(gid) || st->st_gid == gid)) | ||
64 | return 0; | ||
65 | |||
66 | - if (name) | ||
67 | - r = fchownat(fd, name, uid, gid, AT_SYMLINK_NOFOLLOW); | ||
68 | - else | ||
69 | - r = fchown(fd, uid, gid); | ||
70 | - if (r < 0) | ||
71 | - return -errno; | ||
72 | + /* We change ownership through the /proc/self/fd/%i path, so that we have a stable reference that works with | ||
73 | + * O_PATH. (Note: fchown() and fchmod() do not work with O_PATH, the kernel refuses that. */ | ||
74 | + xsprintf(procfs_path, "/proc/self/fd/%i", fd); | ||
75 | |||
76 | - /* The linux kernel alters the mode in some cases of chown(). Let's undo this. */ | ||
77 | - if (name) { | ||
78 | - if (!S_ISLNK(st->st_mode)) | ||
79 | - r = fchmodat(fd, name, st->st_mode, 0); | ||
80 | - else /* There's currently no AT_SYMLINK_NOFOLLOW for fchmodat() */ | ||
81 | - r = 0; | ||
82 | - } else | ||
83 | - r = fchmod(fd, st->st_mode); | ||
84 | - if (r < 0) | ||
85 | + if (chown(procfs_path, uid, gid) < 0) | ||
86 | return -errno; | ||
87 | |||
88 | + /* The linux kernel alters the mode in some cases of chown(). Let's undo this. We do this only for non-symlinks | ||
89 | + * however. That's because for symlinks the access mode is ignored anyway and because on some kernels/file | ||
90 | + * systems trying to change the access mode will succeed but has no effect while on others it actively | ||
91 | + * fails. */ | ||
92 | + if (!S_ISLNK(st->st_mode)) | ||
93 | + if (chmod(procfs_path, st->st_mode & 07777) < 0) | ||
94 | + return -errno; | ||
95 | + | ||
96 | return 1; | ||
97 | } | ||
98 | |||
99 | static int chown_recursive_internal(int fd, const struct stat *st, uid_t uid, gid_t gid) { | ||
100 | + _cleanup_closedir_ DIR *d = NULL; | ||
101 | bool changed = false; | ||
102 | + struct dirent *de; | ||
103 | int r; | ||
104 | |||
105 | assert(fd >= 0); | ||
106 | assert(st); | ||
107 | |||
108 | - if (S_ISDIR(st->st_mode)) { | ||
109 | - _cleanup_closedir_ DIR *d = NULL; | ||
110 | - struct dirent *de; | ||
111 | - | ||
112 | - d = fdopendir(fd); | ||
113 | - if (!d) { | ||
114 | - r = -errno; | ||
115 | - goto finish; | ||
116 | - } | ||
117 | - fd = -1; | ||
118 | - | ||
119 | - FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) { | ||
120 | - struct stat fst; | ||
121 | - | ||
122 | - if (dot_or_dot_dot(de->d_name)) | ||
123 | - continue; | ||
124 | + d = fdopendir(fd); | ||
125 | + if (!d) { | ||
126 | + safe_close(fd); | ||
127 | + return -errno; | ||
128 | + } | ||
129 | |||
130 | - if (fstatat(dirfd(d), de->d_name, &fst, AT_SYMLINK_NOFOLLOW) < 0) { | ||
131 | - r = -errno; | ||
132 | - goto finish; | ||
133 | - } | ||
134 | - | ||
135 | - if (S_ISDIR(fst.st_mode)) { | ||
136 | - int subdir_fd; | ||
137 | - | ||
138 | - subdir_fd = openat(dirfd(d), de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); | ||
139 | - if (subdir_fd < 0) { | ||
140 | - r = -errno; | ||
141 | - goto finish; | ||
142 | - } | ||
143 | - | ||
144 | - r = chown_recursive_internal(subdir_fd, &fst, uid, gid); | ||
145 | - if (r < 0) | ||
146 | - goto finish; | ||
147 | - if (r > 0) | ||
148 | - changed = true; | ||
149 | - } else { | ||
150 | - r = chown_one(dirfd(d), de->d_name, &fst, uid, gid); | ||
151 | - if (r < 0) | ||
152 | - goto finish; | ||
153 | - if (r > 0) | ||
154 | - changed = true; | ||
155 | - } | ||
156 | + FOREACH_DIRENT_ALL(de, d, return -errno) { | ||
157 | + _cleanup_close_ int path_fd = -1; | ||
158 | + struct stat fst; | ||
159 | + | ||
160 | + if (dot_or_dot_dot(de->d_name)) | ||
161 | + continue; | ||
162 | + | ||
163 | + /* Let's pin the child inode we want to fix now with an O_PATH fd, so that it cannot be swapped out | ||
164 | + * while we manipulate it. */ | ||
165 | + path_fd = openat(dirfd(d), de->d_name, O_PATH|O_CLOEXEC|O_NOFOLLOW); | ||
166 | + if (path_fd < 0) | ||
167 | + return -errno; | ||
168 | + | ||
169 | + if (fstat(path_fd, &fst) < 0) | ||
170 | + return -errno; | ||
171 | + | ||
172 | + if (S_ISDIR(fst.st_mode)) { | ||
173 | + int subdir_fd; | ||
174 | + | ||
175 | + /* Convert it to a "real" (i.e. non-O_PATH) fd now */ | ||
176 | + subdir_fd = fd_reopen(path_fd, O_RDONLY|O_CLOEXEC|O_NOATIME); | ||
177 | + if (subdir_fd < 0) | ||
178 | + return subdir_fd; | ||
179 | + | ||
180 | + r = chown_recursive_internal(subdir_fd, &fst, uid, gid); /* takes possession of subdir_fd even on failure */ | ||
181 | + if (r < 0) | ||
182 | + return r; | ||
183 | + if (r > 0) | ||
184 | + changed = true; | ||
185 | + } else { | ||
186 | + r = chown_one(path_fd, &fst, uid, gid); | ||
187 | + if (r < 0) | ||
188 | + return r; | ||
189 | + if (r > 0) | ||
190 | + changed = true; | ||
191 | } | ||
192 | + } | ||
193 | |||
194 | - r = chown_one(dirfd(d), NULL, st, uid, gid); | ||
195 | - } else | ||
196 | - r = chown_one(fd, NULL, st, uid, gid); | ||
197 | + r = chown_one(dirfd(d), st, uid, gid); | ||
198 | if (r < 0) | ||
199 | - goto finish; | ||
200 | - | ||
201 | - r = r > 0 || changed; | ||
202 | + return r; | ||
203 | |||
204 | -finish: | ||
205 | - safe_close(fd); | ||
206 | - return r; | ||
207 | + return r > 0 || changed; | ||
208 | } | ||
209 | |||
210 | int path_chown_recursive(const char *path, uid_t uid, gid_t gid) { | ||
211 | @@ -129,7 +123,7 @@ | ||
212 | struct stat st; | ||
213 | int r; | ||
214 | |||
215 | - fd = open(path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); | ||
216 | + fd = open(path, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW|O_NOATIME); | ||
217 | if (fd < 0) | ||
218 | return -errno; | ||
219 | |||
220 | --- a/src/basic/fd-util.c | ||
221 | +++ b/src/basic/fd-util.c | ||
222 | @@ -578,3 +578,22 @@ | ||
223 | |||
224 | return -EOPNOTSUPP; | ||
225 | } | ||
226 | + | ||
227 | +int fd_reopen(int fd, int flags) { | ||
228 | + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; | ||
229 | + int new_fd; | ||
230 | + | ||
231 | + /* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to | ||
232 | + * turn O_RDWR fds into O_RDONLY fds. | ||
233 | + * | ||
234 | + * This doesn't work on sockets (since they cannot be open()ed, ever). | ||
235 | + * | ||
236 | + * This implicitly resets the file read index to 0. */ | ||
237 | + | ||
238 | + xsprintf(procfs_path, "/proc/self/fd/%i", fd); | ||
239 | + new_fd = open(procfs_path, flags); | ||
240 | + if (new_fd < 0) | ||
241 | + return -errno; | ||
242 | + | ||
243 | + return new_fd; | ||
244 | +} | ||
245 | --- a/src/basic/fd-util.h | ||
246 | +++ b/src/basic/fd-util.h | ||
247 | @@ -91,3 +91,5 @@ | ||
248 | /* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ | ||
249 | #define ERRNO_IS_DISCONNECT(r) \ | ||
250 | IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) | ||
251 | + | ||
252 | +int fd_reopen(int fd, int flags); | ||
diff --git a/meta/recipes-core/systemd/systemd_237.bb b/meta/recipes-core/systemd/systemd_237.bb index a75fae2e15..244776f0b6 100644 --- a/meta/recipes-core/systemd/systemd_237.bb +++ b/meta/recipes-core/systemd/systemd_237.bb | |||
@@ -55,6 +55,7 @@ SRC_URI += "file://touchscreen.rules \ | |||
55 | file://0034-Fix-format-truncation-compile-failure-by-typecasting.patch \ | 55 | file://0034-Fix-format-truncation-compile-failure-by-typecasting.patch \ |
56 | file://0035-Define-glibc-compatible-basename-for-non-glibc-syste.patch \ | 56 | file://0035-Define-glibc-compatible-basename-for-non-glibc-syste.patch \ |
57 | file://0001-core-when-deserializing-state-always-use-read_line-L.patch \ | 57 | file://0001-core-when-deserializing-state-always-use-read_line-L.patch \ |
58 | file://0001-chown-recursive-let-s-rework-the-recursive-logic-to-.patch \ | ||
58 | " | 59 | " |
59 | SRC_URI_append_qemuall = " file://0001-core-device.c-Change-the-default-device-timeout-to-2.patch" | 60 | SRC_URI_append_qemuall = " file://0001-core-device.c-Change-the-default-device-timeout-to-2.patch" |
60 | 61 | ||