Commit 741a295130606143edbf9fc740f633dbc1e6225f
Committed by
Linus Torvalds
1 parent
99d1419d96
Exists in
master
and in
7 other branches
[PATCH] unshare system call -v5: unshare namespace
If the namespace structure is being shared, allocate a new one and copy information from the current, shared, structure. Signed-off-by: Janak Desai <janak@us.ibm.com> Cc: Al Viro <viro@ftp.linux.org.uk> Cc: Christoph Hellwig <hch@lst.de> Cc: Michael Kerrisk <mtk-manpages@gmx.net> Cc: Andi Kleen <ak@muc.de> Cc: Paul Mackerras <paulus@samba.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 3 changed files with 48 additions and 26 deletions Side-by-side Diff
fs/namespace.c
... | ... | @@ -1325,27 +1325,17 @@ |
1325 | 1325 | return retval; |
1326 | 1326 | } |
1327 | 1327 | |
1328 | -int copy_namespace(int flags, struct task_struct *tsk) | |
1328 | +/* | |
1329 | + * Allocate a new namespace structure and populate it with contents | |
1330 | + * copied from the namespace of the passed in task structure. | |
1331 | + */ | |
1332 | +struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs) | |
1329 | 1333 | { |
1330 | 1334 | struct namespace *namespace = tsk->namespace; |
1331 | 1335 | struct namespace *new_ns; |
1332 | 1336 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; |
1333 | - struct fs_struct *fs = tsk->fs; | |
1334 | 1337 | struct vfsmount *p, *q; |
1335 | 1338 | |
1336 | - if (!namespace) | |
1337 | - return 0; | |
1338 | - | |
1339 | - get_namespace(namespace); | |
1340 | - | |
1341 | - if (!(flags & CLONE_NEWNS)) | |
1342 | - return 0; | |
1343 | - | |
1344 | - if (!capable(CAP_SYS_ADMIN)) { | |
1345 | - put_namespace(namespace); | |
1346 | - return -EPERM; | |
1347 | - } | |
1348 | - | |
1349 | 1339 | new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL); |
1350 | 1340 | if (!new_ns) |
1351 | 1341 | goto out; |
... | ... | @@ -1396,8 +1386,6 @@ |
1396 | 1386 | } |
1397 | 1387 | up_write(&namespace_sem); |
1398 | 1388 | |
1399 | - tsk->namespace = new_ns; | |
1400 | - | |
1401 | 1389 | if (rootmnt) |
1402 | 1390 | mntput(rootmnt); |
1403 | 1391 | if (pwdmnt) |
1404 | 1392 | |
1405 | 1393 | |
... | ... | @@ -1405,12 +1393,40 @@ |
1405 | 1393 | if (altrootmnt) |
1406 | 1394 | mntput(altrootmnt); |
1407 | 1395 | |
1408 | - put_namespace(namespace); | |
1409 | - return 0; | |
1396 | +out: | |
1397 | + return new_ns; | |
1398 | +} | |
1410 | 1399 | |
1400 | +int copy_namespace(int flags, struct task_struct *tsk) | |
1401 | +{ | |
1402 | + struct namespace *namespace = tsk->namespace; | |
1403 | + struct namespace *new_ns; | |
1404 | + int err = 0; | |
1405 | + | |
1406 | + if (!namespace) | |
1407 | + return 0; | |
1408 | + | |
1409 | + get_namespace(namespace); | |
1410 | + | |
1411 | + if (!(flags & CLONE_NEWNS)) | |
1412 | + return 0; | |
1413 | + | |
1414 | + if (!capable(CAP_SYS_ADMIN)) { | |
1415 | + err = -EPERM; | |
1416 | + goto out; | |
1417 | + } | |
1418 | + | |
1419 | + new_ns = dup_namespace(tsk, tsk->fs); | |
1420 | + if (!new_ns) { | |
1421 | + err = -ENOMEM; | |
1422 | + goto out; | |
1423 | + } | |
1424 | + | |
1425 | + tsk->namespace = new_ns; | |
1426 | + | |
1411 | 1427 | out: |
1412 | 1428 | put_namespace(namespace); |
1413 | - return -ENOMEM; | |
1429 | + return err; | |
1414 | 1430 | } |
1415 | 1431 | |
1416 | 1432 | asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name, |
include/linux/namespace.h
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | |
16 | 16 | extern int copy_namespace(int, struct task_struct *); |
17 | 17 | extern void __put_namespace(struct namespace *namespace); |
18 | +extern struct namespace *dup_namespace(struct task_struct *, struct fs_struct *); | |
18 | 19 | |
19 | 20 | static inline void put_namespace(struct namespace *namespace) |
20 | 21 | { |
kernel/fork.c
... | ... | @@ -1388,17 +1388,22 @@ |
1388 | 1388 | } |
1389 | 1389 | |
1390 | 1390 | /* |
1391 | - * Unsharing of namespace for tasks created without CLONE_NEWNS is not | |
1392 | - * supported yet | |
1391 | + * Unshare the namespace structure if it is being shared | |
1393 | 1392 | */ |
1394 | -static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp) | |
1393 | +static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs) | |
1395 | 1394 | { |
1396 | 1395 | struct namespace *ns = current->namespace; |
1397 | 1396 | |
1398 | 1397 | if ((unshare_flags & CLONE_NEWNS) && |
1399 | - (ns && atomic_read(&ns->count) > 1)) | |
1400 | - return -EINVAL; | |
1398 | + (ns && atomic_read(&ns->count) > 1)) { | |
1399 | + if (!capable(CAP_SYS_ADMIN)) | |
1400 | + return -EPERM; | |
1401 | 1401 | |
1402 | + *new_nsp = dup_namespace(current, new_fs ? new_fs : current->fs); | |
1403 | + if (!*new_nsp) | |
1404 | + return -ENOMEM; | |
1405 | + } | |
1406 | + | |
1402 | 1407 | return 0; |
1403 | 1408 | } |
1404 | 1409 | |
... | ... | @@ -1482,7 +1487,7 @@ |
1482 | 1487 | goto bad_unshare_out; |
1483 | 1488 | if ((err = unshare_fs(unshare_flags, &new_fs))) |
1484 | 1489 | goto bad_unshare_cleanup_thread; |
1485 | - if ((err = unshare_namespace(unshare_flags, &new_ns))) | |
1490 | + if ((err = unshare_namespace(unshare_flags, &new_ns, new_fs))) | |
1486 | 1491 | goto bad_unshare_cleanup_fs; |
1487 | 1492 | if ((err = unshare_sighand(unshare_flags, &new_sigh))) |
1488 | 1493 | goto bad_unshare_cleanup_ns; |