diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-24 12:25:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-24 12:25:39 -0400 |
commit | 4def1963608ed2b61aca5b52fdedb4ca2798820c (patch) | |
tree | 83b36e8ff3c5eabe0d235f863adcf54f838f838a /kernel | |
parent | 5e8704ac1cfa9fceef94fcc457e18613b1589b34 (diff) | |
parent | 82c9a927bc5df6e06b72d206d24a9d10cced4eb5 (diff) |
Merge branch 'userns-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace
Pull namespace fixes from Eric Biederman:
"This is a set of four fairly obvious bug fixes:
- a switch from d_find_alias to d_find_any_alias because the xattr
code perversely takes a dentry
- two mutex vs copy_to_user fixes from Jann Horn
- a fix to use a sanitized size not the size userspace passed in from
Christian Brauner"
* 'userns-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
getxattr: use correct xattr length
sys: don't hold uts_sem while accessing userspace memory
userns: move user access out of the mutex
cap_inode_getsecurity: use d_find_any_alias() instead of d_find_alias()
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sys.c | 95 | ||||
-rw-r--r-- | kernel/user_namespace.c | 24 | ||||
-rw-r--r-- | kernel/utsname_sysctl.c | 41 |
3 files changed, 80 insertions, 80 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index e27b51d3facd..cf5c67533ff1 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1237,18 +1237,19 @@ static int override_release(char __user *release, size_t len) | |||
1237 | 1237 | ||
1238 | SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) | 1238 | SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) |
1239 | { | 1239 | { |
1240 | int errno = 0; | 1240 | struct new_utsname tmp; |
1241 | 1241 | ||
1242 | down_read(&uts_sem); | 1242 | down_read(&uts_sem); |
1243 | if (copy_to_user(name, utsname(), sizeof *name)) | 1243 | memcpy(&tmp, utsname(), sizeof(tmp)); |
1244 | errno = -EFAULT; | ||
1245 | up_read(&uts_sem); | 1244 | up_read(&uts_sem); |
1245 | if (copy_to_user(name, &tmp, sizeof(tmp))) | ||
1246 | return -EFAULT; | ||
1246 | 1247 | ||
1247 | if (!errno && override_release(name->release, sizeof(name->release))) | 1248 | if (override_release(name->release, sizeof(name->release))) |
1248 | errno = -EFAULT; | 1249 | return -EFAULT; |
1249 | if (!errno && override_architecture(name)) | 1250 | if (override_architecture(name)) |
1250 | errno = -EFAULT; | 1251 | return -EFAULT; |
1251 | return errno; | 1252 | return 0; |
1252 | } | 1253 | } |
1253 | 1254 | ||
1254 | #ifdef __ARCH_WANT_SYS_OLD_UNAME | 1255 | #ifdef __ARCH_WANT_SYS_OLD_UNAME |
@@ -1257,55 +1258,46 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) | |||
1257 | */ | 1258 | */ |
1258 | SYSCALL_DEFINE1(uname, struct old_utsname __user *, name) | 1259 | SYSCALL_DEFINE1(uname, struct old_utsname __user *, name) |
1259 | { | 1260 | { |
1260 | int error = 0; | 1261 | struct old_utsname tmp; |
1261 | 1262 | ||
1262 | if (!name) | 1263 | if (!name) |
1263 | return -EFAULT; | 1264 | return -EFAULT; |
1264 | 1265 | ||
1265 | down_read(&uts_sem); | 1266 | down_read(&uts_sem); |
1266 | if (copy_to_user(name, utsname(), sizeof(*name))) | 1267 | memcpy(&tmp, utsname(), sizeof(tmp)); |
1267 | error = -EFAULT; | ||
1268 | up_read(&uts_sem); | 1268 | up_read(&uts_sem); |
1269 | if (copy_to_user(name, &tmp, sizeof(tmp))) | ||
1270 | return -EFAULT; | ||
1269 | 1271 | ||
1270 | if (!error && override_release(name->release, sizeof(name->release))) | 1272 | if (override_release(name->release, sizeof(name->release))) |
1271 | error = -EFAULT; | 1273 | return -EFAULT; |
1272 | if (!error && override_architecture(name)) | 1274 | if (override_architecture(name)) |
1273 | error = -EFAULT; | 1275 | return -EFAULT; |
1274 | return error; | 1276 | return 0; |
1275 | } | 1277 | } |
1276 | 1278 | ||
1277 | SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name) | 1279 | SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name) |
1278 | { | 1280 | { |
1279 | int error; | 1281 | struct oldold_utsname tmp = {}; |
1280 | 1282 | ||
1281 | if (!name) | 1283 | if (!name) |
1282 | return -EFAULT; | 1284 | return -EFAULT; |
1283 | if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname))) | ||
1284 | return -EFAULT; | ||
1285 | 1285 | ||
1286 | down_read(&uts_sem); | 1286 | down_read(&uts_sem); |
1287 | error = __copy_to_user(&name->sysname, &utsname()->sysname, | 1287 | memcpy(&tmp.sysname, &utsname()->sysname, __OLD_UTS_LEN); |
1288 | __OLD_UTS_LEN); | 1288 | memcpy(&tmp.nodename, &utsname()->nodename, __OLD_UTS_LEN); |
1289 | error |= __put_user(0, name->sysname + __OLD_UTS_LEN); | 1289 | memcpy(&tmp.release, &utsname()->release, __OLD_UTS_LEN); |
1290 | error |= __copy_to_user(&name->nodename, &utsname()->nodename, | 1290 | memcpy(&tmp.version, &utsname()->version, __OLD_UTS_LEN); |
1291 | __OLD_UTS_LEN); | 1291 | memcpy(&tmp.machine, &utsname()->machine, __OLD_UTS_LEN); |
1292 | error |= __put_user(0, name->nodename + __OLD_UTS_LEN); | ||
1293 | error |= __copy_to_user(&name->release, &utsname()->release, | ||
1294 | __OLD_UTS_LEN); | ||
1295 | error |= __put_user(0, name->release + __OLD_UTS_LEN); | ||
1296 | error |= __copy_to_user(&name->version, &utsname()->version, | ||
1297 | __OLD_UTS_LEN); | ||
1298 | error |= __put_user(0, name->version + __OLD_UTS_LEN); | ||
1299 | error |= __copy_to_user(&name->machine, &utsname()->machine, | ||
1300 | __OLD_UTS_LEN); | ||
1301 | error |= __put_user(0, name->machine + __OLD_UTS_LEN); | ||
1302 | up_read(&uts_sem); | 1292 | up_read(&uts_sem); |
1293 | if (copy_to_user(name, &tmp, sizeof(tmp))) | ||
1294 | return -EFAULT; | ||
1303 | 1295 | ||
1304 | if (!error && override_architecture(name)) | 1296 | if (override_architecture(name)) |
1305 | error = -EFAULT; | 1297 | return -EFAULT; |
1306 | if (!error && override_release(name->release, sizeof(name->release))) | 1298 | if (override_release(name->release, sizeof(name->release))) |
1307 | error = -EFAULT; | 1299 | return -EFAULT; |
1308 | return error ? -EFAULT : 0; | 1300 | return 0; |
1309 | } | 1301 | } |
1310 | #endif | 1302 | #endif |
1311 | 1303 | ||
@@ -1319,17 +1311,18 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) | |||
1319 | 1311 | ||
1320 | if (len < 0 || len > __NEW_UTS_LEN) | 1312 | if (len < 0 || len > __NEW_UTS_LEN) |
1321 | return -EINVAL; | 1313 | return -EINVAL; |
1322 | down_write(&uts_sem); | ||
1323 | errno = -EFAULT; | 1314 | errno = -EFAULT; |
1324 | if (!copy_from_user(tmp, name, len)) { | 1315 | if (!copy_from_user(tmp, name, len)) { |
1325 | struct new_utsname *u = utsname(); | 1316 | struct new_utsname *u; |
1326 | 1317 | ||
1318 | down_write(&uts_sem); | ||
1319 | u = utsname(); | ||
1327 | memcpy(u->nodename, tmp, len); | 1320 | memcpy(u->nodename, tmp, len); |
1328 | memset(u->nodename + len, 0, sizeof(u->nodename) - len); | 1321 | memset(u->nodename + len, 0, sizeof(u->nodename) - len); |
1329 | errno = 0; | 1322 | errno = 0; |
1330 | uts_proc_notify(UTS_PROC_HOSTNAME); | 1323 | uts_proc_notify(UTS_PROC_HOSTNAME); |
1324 | up_write(&uts_sem); | ||
1331 | } | 1325 | } |
1332 | up_write(&uts_sem); | ||
1333 | return errno; | 1326 | return errno; |
1334 | } | 1327 | } |
1335 | 1328 | ||
@@ -1337,8 +1330,9 @@ SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) | |||
1337 | 1330 | ||
1338 | SYSCALL_DEFINE2(gethostname, char __user *, name, int, len) | 1331 | SYSCALL_DEFINE2(gethostname, char __user *, name, int, len) |
1339 | { | 1332 | { |
1340 | int i, errno; | 1333 | int i; |
1341 | struct new_utsname *u; | 1334 | struct new_utsname *u; |
1335 | char tmp[__NEW_UTS_LEN + 1]; | ||
1342 | 1336 | ||
1343 | if (len < 0) | 1337 | if (len < 0) |
1344 | return -EINVAL; | 1338 | return -EINVAL; |
@@ -1347,11 +1341,11 @@ SYSCALL_DEFINE2(gethostname, char __user *, name, int, len) | |||
1347 | i = 1 + strlen(u->nodename); | 1341 | i = 1 + strlen(u->nodename); |
1348 | if (i > len) | 1342 | if (i > len) |
1349 | i = len; | 1343 | i = len; |
1350 | errno = 0; | 1344 | memcpy(tmp, u->nodename, i); |
1351 | if (copy_to_user(name, u->nodename, i)) | ||
1352 | errno = -EFAULT; | ||
1353 | up_read(&uts_sem); | 1345 | up_read(&uts_sem); |
1354 | return errno; | 1346 | if (copy_to_user(name, tmp, i)) |
1347 | return -EFAULT; | ||
1348 | return 0; | ||
1355 | } | 1349 | } |
1356 | 1350 | ||
1357 | #endif | 1351 | #endif |
@@ -1370,17 +1364,18 @@ SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) | |||
1370 | if (len < 0 || len > __NEW_UTS_LEN) | 1364 | if (len < 0 || len > __NEW_UTS_LEN) |
1371 | return -EINVAL; | 1365 | return -EINVAL; |
1372 | 1366 | ||
1373 | down_write(&uts_sem); | ||
1374 | errno = -EFAULT; | 1367 | errno = -EFAULT; |
1375 | if (!copy_from_user(tmp, name, len)) { | 1368 | if (!copy_from_user(tmp, name, len)) { |
1376 | struct new_utsname *u = utsname(); | 1369 | struct new_utsname *u; |
1377 | 1370 | ||
1371 | down_write(&uts_sem); | ||
1372 | u = utsname(); | ||
1378 | memcpy(u->domainname, tmp, len); | 1373 | memcpy(u->domainname, tmp, len); |
1379 | memset(u->domainname + len, 0, sizeof(u->domainname) - len); | 1374 | memset(u->domainname + len, 0, sizeof(u->domainname) - len); |
1380 | errno = 0; | 1375 | errno = 0; |
1381 | uts_proc_notify(UTS_PROC_DOMAINNAME); | 1376 | uts_proc_notify(UTS_PROC_DOMAINNAME); |
1377 | up_write(&uts_sem); | ||
1382 | } | 1378 | } |
1383 | up_write(&uts_sem); | ||
1384 | return errno; | 1379 | return errno; |
1385 | } | 1380 | } |
1386 | 1381 | ||
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index c3d7583fcd21..e5222b5fb4fe 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c | |||
@@ -859,7 +859,16 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
859 | unsigned idx; | 859 | unsigned idx; |
860 | struct uid_gid_extent extent; | 860 | struct uid_gid_extent extent; |
861 | char *kbuf = NULL, *pos, *next_line; | 861 | char *kbuf = NULL, *pos, *next_line; |
862 | ssize_t ret = -EINVAL; | 862 | ssize_t ret; |
863 | |||
864 | /* Only allow < page size writes at the beginning of the file */ | ||
865 | if ((*ppos != 0) || (count >= PAGE_SIZE)) | ||
866 | return -EINVAL; | ||
867 | |||
868 | /* Slurp in the user data */ | ||
869 | kbuf = memdup_user_nul(buf, count); | ||
870 | if (IS_ERR(kbuf)) | ||
871 | return PTR_ERR(kbuf); | ||
863 | 872 | ||
864 | /* | 873 | /* |
865 | * The userns_state_mutex serializes all writes to any given map. | 874 | * The userns_state_mutex serializes all writes to any given map. |
@@ -895,19 +904,6 @@ static ssize_t map_write(struct file *file, const char __user *buf, | |||
895 | if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN)) | 904 | if (cap_valid(cap_setid) && !file_ns_capable(file, ns, CAP_SYS_ADMIN)) |
896 | goto out; | 905 | goto out; |
897 | 906 | ||
898 | /* Only allow < page size writes at the beginning of the file */ | ||
899 | ret = -EINVAL; | ||
900 | if ((*ppos != 0) || (count >= PAGE_SIZE)) | ||
901 | goto out; | ||
902 | |||
903 | /* Slurp in the user data */ | ||
904 | kbuf = memdup_user_nul(buf, count); | ||
905 | if (IS_ERR(kbuf)) { | ||
906 | ret = PTR_ERR(kbuf); | ||
907 | kbuf = NULL; | ||
908 | goto out; | ||
909 | } | ||
910 | |||
911 | /* Parse the user data */ | 907 | /* Parse the user data */ |
912 | ret = -EINVAL; | 908 | ret = -EINVAL; |
913 | pos = kbuf; | 909 | pos = kbuf; |
diff --git a/kernel/utsname_sysctl.c b/kernel/utsname_sysctl.c index 233cd8fc6910..258033d62cb3 100644 --- a/kernel/utsname_sysctl.c +++ b/kernel/utsname_sysctl.c | |||
@@ -18,7 +18,7 @@ | |||
18 | 18 | ||
19 | #ifdef CONFIG_PROC_SYSCTL | 19 | #ifdef CONFIG_PROC_SYSCTL |
20 | 20 | ||
21 | static void *get_uts(struct ctl_table *table, int write) | 21 | static void *get_uts(struct ctl_table *table) |
22 | { | 22 | { |
23 | char *which = table->data; | 23 | char *which = table->data; |
24 | struct uts_namespace *uts_ns; | 24 | struct uts_namespace *uts_ns; |
@@ -26,21 +26,9 @@ static void *get_uts(struct ctl_table *table, int write) | |||
26 | uts_ns = current->nsproxy->uts_ns; | 26 | uts_ns = current->nsproxy->uts_ns; |
27 | which = (which - (char *)&init_uts_ns) + (char *)uts_ns; | 27 | which = (which - (char *)&init_uts_ns) + (char *)uts_ns; |
28 | 28 | ||
29 | if (!write) | ||
30 | down_read(&uts_sem); | ||
31 | else | ||
32 | down_write(&uts_sem); | ||
33 | return which; | 29 | return which; |
34 | } | 30 | } |
35 | 31 | ||
36 | static void put_uts(struct ctl_table *table, int write, void *which) | ||
37 | { | ||
38 | if (!write) | ||
39 | up_read(&uts_sem); | ||
40 | else | ||
41 | up_write(&uts_sem); | ||
42 | } | ||
43 | |||
44 | /* | 32 | /* |
45 | * Special case of dostring for the UTS structure. This has locks | 33 | * Special case of dostring for the UTS structure. This has locks |
46 | * to observe. Should this be in kernel/sys.c ???? | 34 | * to observe. Should this be in kernel/sys.c ???? |
@@ -50,13 +38,34 @@ static int proc_do_uts_string(struct ctl_table *table, int write, | |||
50 | { | 38 | { |
51 | struct ctl_table uts_table; | 39 | struct ctl_table uts_table; |
52 | int r; | 40 | int r; |
41 | char tmp_data[__NEW_UTS_LEN + 1]; | ||
42 | |||
53 | memcpy(&uts_table, table, sizeof(uts_table)); | 43 | memcpy(&uts_table, table, sizeof(uts_table)); |
54 | uts_table.data = get_uts(table, write); | 44 | uts_table.data = tmp_data; |
45 | |||
46 | /* | ||
47 | * Buffer the value in tmp_data so that proc_dostring() can be called | ||
48 | * without holding any locks. | ||
49 | * We also need to read the original value in the write==1 case to | ||
50 | * support partial writes. | ||
51 | */ | ||
52 | down_read(&uts_sem); | ||
53 | memcpy(tmp_data, get_uts(table), sizeof(tmp_data)); | ||
54 | up_read(&uts_sem); | ||
55 | r = proc_dostring(&uts_table, write, buffer, lenp, ppos); | 55 | r = proc_dostring(&uts_table, write, buffer, lenp, ppos); |
56 | put_uts(table, write, uts_table.data); | ||
57 | 56 | ||
58 | if (write) | 57 | if (write) { |
58 | /* | ||
59 | * Write back the new value. | ||
60 | * Note that, since we dropped uts_sem, the result can | ||
61 | * theoretically be incorrect if there are two parallel writes | ||
62 | * at non-zero offsets to the same sysctl. | ||
63 | */ | ||
64 | down_write(&uts_sem); | ||
65 | memcpy(get_uts(table), tmp_data, sizeof(tmp_data)); | ||
66 | up_write(&uts_sem); | ||
59 | proc_sys_poll_notify(table->poll); | 67 | proc_sys_poll_notify(table->poll); |
68 | } | ||
60 | 69 | ||
61 | return r; | 70 | return r; |
62 | } | 71 | } |