2006-10-02 13:18:06 +04:00
/*
* Copyright ( C ) 2006 IBM Corporation
*
* Author : Serge Hallyn < serue @ us . ibm . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation , version 2 of the
* License .
2006-10-02 13:18:19 +04:00
*
* Jun 2006 - namespaces support
* OpenVZ , SWsoft Inc .
* Pavel Emelianov < xemul @ openvz . org >
2006-10-02 13:18:06 +04:00
*/
# include <linux/module.h>
# include <linux/version.h>
# include <linux/nsproxy.h>
2006-10-02 13:18:07 +04:00
# include <linux/init_task.h>
2006-12-08 13:37:56 +03:00
# include <linux/mnt_namespace.h>
2006-10-02 13:18:14 +04:00
# include <linux/utsname.h>
2006-12-08 13:37:59 +03:00
# include <linux/pid_namespace.h>
2006-10-02 13:18:07 +04:00
struct nsproxy init_nsproxy = INIT_NSPROXY ( init_nsproxy ) ;
2006-10-02 13:18:06 +04:00
static inline void get_nsproxy ( struct nsproxy * ns )
{
atomic_inc ( & ns - > count ) ;
}
void get_task_namespaces ( struct task_struct * tsk )
{
struct nsproxy * ns = tsk - > nsproxy ;
if ( ns ) {
get_nsproxy ( ns ) ;
}
}
/*
* creates a copy of " orig " with refcount 1.
*/
2007-05-08 11:25:21 +04:00
static inline struct nsproxy * clone_nsproxy ( struct nsproxy * orig )
2006-10-02 13:18:06 +04:00
{
struct nsproxy * ns ;
2006-10-20 10:29:12 +04:00
ns = kmemdup ( orig , sizeof ( struct nsproxy ) , GFP_KERNEL ) ;
2006-12-13 11:34:04 +03:00
if ( ns )
2006-10-02 13:18:06 +04:00
atomic_set ( & ns - > count , 1 ) ;
return ns ;
}
/*
2007-05-08 11:25:21 +04:00
* Create new nsproxy and all of its the associated namespaces .
* Return the newly created nsproxy . Do not attach this to the task ,
* leave it to the caller to do proper locking and attach it to task .
2006-10-02 13:18:06 +04:00
*/
2007-05-08 11:25:21 +04:00
static struct nsproxy * create_new_namespaces ( int flags , struct task_struct * tsk ,
struct fs_struct * new_fs )
2006-10-02 13:18:06 +04:00
{
2007-05-08 11:25:21 +04:00
struct nsproxy * new_nsp ;
2006-10-02 13:18:06 +04:00
2007-05-08 11:25:21 +04:00
new_nsp = clone_nsproxy ( tsk - > nsproxy ) ;
if ( ! new_nsp )
return ERR_PTR ( - ENOMEM ) ;
2006-10-02 13:18:08 +04:00
2007-05-08 11:25:21 +04:00
new_nsp - > mnt_ns = copy_mnt_ns ( flags , tsk - > nsproxy - > mnt_ns , new_fs ) ;
if ( IS_ERR ( new_nsp - > mnt_ns ) )
goto out_ns ;
new_nsp - > uts_ns = copy_utsname ( flags , tsk - > nsproxy - > uts_ns ) ;
if ( IS_ERR ( new_nsp - > uts_ns ) )
goto out_uts ;
new_nsp - > ipc_ns = copy_ipcs ( flags , tsk - > nsproxy - > ipc_ns ) ;
if ( IS_ERR ( new_nsp - > ipc_ns ) )
goto out_ipc ;
new_nsp - > pid_ns = copy_pid_ns ( flags , tsk - > nsproxy - > pid_ns ) ;
if ( IS_ERR ( new_nsp - > pid_ns ) )
goto out_pid ;
return new_nsp ;
out_pid :
if ( new_nsp - > ipc_ns )
put_ipc_ns ( new_nsp - > ipc_ns ) ;
out_ipc :
if ( new_nsp - > uts_ns )
put_uts_ns ( new_nsp - > uts_ns ) ;
out_uts :
if ( new_nsp - > mnt_ns )
put_mnt_ns ( new_nsp - > mnt_ns ) ;
out_ns :
kfree ( new_nsp ) ;
return ERR_PTR ( - ENOMEM ) ;
2006-10-02 13:18:06 +04:00
}
/*
* called from clone . This now handles copy for nsproxy and all
* namespaces therein .
*/
int copy_namespaces ( int flags , struct task_struct * tsk )
{
struct nsproxy * old_ns = tsk - > nsproxy ;
2006-10-02 13:18:08 +04:00
struct nsproxy * new_ns ;
int err = 0 ;
2006-10-02 13:18:06 +04:00
if ( ! old_ns )
return 0 ;
get_nsproxy ( old_ns ) ;
2006-10-02 13:18:19 +04:00
if ( ! ( flags & ( CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC ) ) )
2006-10-02 13:18:08 +04:00
return 0 ;
2007-05-08 11:25:21 +04:00
if ( ! capable ( CAP_SYS_ADMIN ) ) {
err = - EPERM ;
2006-10-02 13:18:08 +04:00
goto out ;
}
2007-05-08 11:25:21 +04:00
new_ns = create_new_namespaces ( flags , tsk , tsk - > fs ) ;
if ( IS_ERR ( new_ns ) ) {
err = PTR_ERR ( new_ns ) ;
goto out ;
}
2006-12-08 13:37:59 +03:00
2007-05-08 11:25:21 +04:00
tsk - > nsproxy = new_ns ;
2006-10-02 13:18:08 +04:00
out :
2007-01-31 00:35:18 +03:00
put_nsproxy ( old_ns ) ;
2006-10-02 13:18:08 +04:00
return err ;
2006-10-02 13:18:06 +04:00
}
void free_nsproxy ( struct nsproxy * ns )
{
2006-12-08 13:37:59 +03:00
if ( ns - > mnt_ns )
put_mnt_ns ( ns - > mnt_ns ) ;
if ( ns - > uts_ns )
put_uts_ns ( ns - > uts_ns ) ;
if ( ns - > ipc_ns )
put_ipc_ns ( ns - > ipc_ns ) ;
if ( ns - > pid_ns )
put_pid_ns ( ns - > pid_ns ) ;
kfree ( ns ) ;
2006-10-02 13:18:06 +04:00
}
2007-05-08 11:25:21 +04:00
/*
* Called from unshare . Unshare all the namespaces part of nsproxy .
2007-06-24 04:16:25 +04:00
* On success , returns the new nsproxy .
2007-05-08 11:25:21 +04:00
*/
int unshare_nsproxy_namespaces ( unsigned long unshare_flags ,
struct nsproxy * * new_nsp , struct fs_struct * new_fs )
{
int err = 0 ;
if ( ! ( unshare_flags & ( CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC ) ) )
return 0 ;
if ( ! capable ( CAP_SYS_ADMIN ) )
return - EPERM ;
* new_nsp = create_new_namespaces ( unshare_flags , current ,
new_fs ? new_fs : current - > fs ) ;
2007-06-24 04:16:25 +04:00
if ( IS_ERR ( * new_nsp ) )
2007-05-08 11:25:21 +04:00
err = PTR_ERR ( * new_nsp ) ;
return err ;
}