aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJANAK DESAI <janak@us.ibm.com>2006-02-07 15:59:00 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-07 19:12:34 -0500
commit741a295130606143edbf9fc740f633dbc1e6225f (patch)
tree3679047dd44e94ba94ee1487880a94def93a06f9
parent99d1419d96d7df9cfa56bc977810be831bd5ef64 (diff)
[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>
-rw-r--r--fs/namespace.c56
-rw-r--r--include/linux/namespace.h1
-rw-r--r--kernel/fork.c17
3 files changed, 48 insertions, 26 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index ce97becff461..a2bef5c81033 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1325,27 +1325,17 @@ dput_out:
1325 return retval; 1325 return retval;
1326} 1326}
1327 1327
1328int 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 */
1332struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
1329{ 1333{
1330 struct namespace *namespace = tsk->namespace; 1334 struct namespace *namespace = tsk->namespace;
1331 struct namespace *new_ns; 1335 struct namespace *new_ns;
1332 struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL; 1336 struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
1333 struct fs_struct *fs = tsk->fs;
1334 struct vfsmount *p, *q; 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 new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL); 1339 new_ns = kmalloc(sizeof(struct namespace), GFP_KERNEL);
1350 if (!new_ns) 1340 if (!new_ns)
1351 goto out; 1341 goto out;
@@ -1396,8 +1386,6 @@ int copy_namespace(int flags, struct task_struct *tsk)
1396 } 1386 }
1397 up_write(&namespace_sem); 1387 up_write(&namespace_sem);
1398 1388
1399 tsk->namespace = new_ns;
1400
1401 if (rootmnt) 1389 if (rootmnt)
1402 mntput(rootmnt); 1390 mntput(rootmnt);
1403 if (pwdmnt) 1391 if (pwdmnt)
@@ -1405,12 +1393,40 @@ int copy_namespace(int flags, struct task_struct *tsk)
1405 if (altrootmnt) 1393 if (altrootmnt)
1406 mntput(altrootmnt); 1394 mntput(altrootmnt);
1407 1395
1408 put_namespace(namespace); 1396out:
1409 return 0; 1397 return new_ns;
1398}
1399
1400int 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;
1410 1426
1411out: 1427out:
1412 put_namespace(namespace); 1428 put_namespace(namespace);
1413 return -ENOMEM; 1429 return err;
1414} 1430}
1415 1431
1416asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name, 1432asmlinkage long sys_mount(char __user * dev_name, char __user * dir_name,
diff --git a/include/linux/namespace.h b/include/linux/namespace.h
index 6731977c4c13..3abc8e3b4879 100644
--- a/include/linux/namespace.h
+++ b/include/linux/namespace.h
@@ -15,6 +15,7 @@ struct namespace {
15 15
16extern int copy_namespace(int, struct task_struct *); 16extern int copy_namespace(int, struct task_struct *);
17extern void __put_namespace(struct namespace *namespace); 17extern void __put_namespace(struct namespace *namespace);
18extern struct namespace *dup_namespace(struct task_struct *, struct fs_struct *);
18 19
19static inline void put_namespace(struct namespace *namespace) 20static inline void put_namespace(struct namespace *namespace)
20{ 21{
diff --git a/kernel/fork.c b/kernel/fork.c
index 598e5c27242c..07dd241aa1e0 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1388,16 +1388,21 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
1388} 1388}
1389 1389
1390/* 1390/*
1391 * Unsharing of namespace for tasks created without CLONE_NEWNS is not 1391 * Unshare the namespace structure if it is being shared
1392 * supported yet
1393 */ 1392 */
1394static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp) 1393static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs)
1395{ 1394{
1396 struct namespace *ns = current->namespace; 1395 struct namespace *ns = current->namespace;
1397 1396
1398 if ((unshare_flags & CLONE_NEWNS) && 1397 if ((unshare_flags & CLONE_NEWNS) &&
1399 (ns && atomic_read(&ns->count) > 1)) 1398 (ns && atomic_read(&ns->count) > 1)) {
1400 return -EINVAL; 1399 if (!capable(CAP_SYS_ADMIN))
1400 return -EPERM;
1401
1402 *new_nsp = dup_namespace(current, new_fs ? new_fs : current->fs);
1403 if (!*new_nsp)
1404 return -ENOMEM;
1405 }
1401 1406
1402 return 0; 1407 return 0;
1403} 1408}
@@ -1482,7 +1487,7 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
1482 goto bad_unshare_out; 1487 goto bad_unshare_out;
1483 if ((err = unshare_fs(unshare_flags, &new_fs))) 1488 if ((err = unshare_fs(unshare_flags, &new_fs)))
1484 goto bad_unshare_cleanup_thread; 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 goto bad_unshare_cleanup_fs; 1491 goto bad_unshare_cleanup_fs;
1487 if ((err = unshare_sighand(unshare_flags, &new_sigh))) 1492 if ((err = unshare_sighand(unshare_flags, &new_sigh)))
1488 goto bad_unshare_cleanup_ns; 1493 goto bad_unshare_cleanup_ns;