mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	[PATCH] IPC namespace core
This patch set allows to unshare IPCs and have a private set of IPC objects (sem, shm, msg) inside namespace. Basically, it is another building block of containers functionality. This patch implements core IPC namespace changes: - ipc_namespace structure - new config option CONFIG_IPC_NS - adds CLONE_NEWIPC flag - unshare support [clg@fr.ibm.com: small fix for unshare of ipc namespace] [akpm@osdl.org: build fix] Signed-off-by: Pavel Emelianov <xemul@openvz.org> Signed-off-by: Kirill Korotaev <dev@openvz.org> Signed-off-by: Cedric Le Goater <clg@fr.ibm.com> Cc: "Eric W. Biederman" <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
		
							parent
							
								
									c0b2fc3165
								
							
						
					
					
						commit
						25b21cb2f6
					
				
					 7 changed files with 95 additions and 17 deletions
				
			
		| 
						 | 
					@ -74,6 +74,7 @@ extern struct nsproxy init_nsproxy;
 | 
				
			||||||
	.count		= ATOMIC_INIT(1),				\
 | 
						.count		= ATOMIC_INIT(1),				\
 | 
				
			||||||
	.nslock		= SPIN_LOCK_UNLOCKED,				\
 | 
						.nslock		= SPIN_LOCK_UNLOCKED,				\
 | 
				
			||||||
	.uts_ns		= &init_uts_ns,					\
 | 
						.uts_ns		= &init_uts_ns,					\
 | 
				
			||||||
 | 
						.ipc_ns		= &init_ipc_ns,					\
 | 
				
			||||||
	.namespace	= NULL,						\
 | 
						.namespace	= NULL,						\
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,6 +2,7 @@
 | 
				
			||||||
#define _LINUX_IPC_H
 | 
					#define _LINUX_IPC_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/types.h>
 | 
				
			||||||
 | 
					#include <linux/kref.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define IPC_PRIVATE ((__kernel_key_t) 0)  
 | 
					#define IPC_PRIVATE ((__kernel_key_t) 0)  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,6 +69,41 @@ struct kern_ipc_perm
 | 
				
			||||||
	void		*security;
 | 
						void		*security;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct ipc_ids;
 | 
				
			||||||
 | 
					struct ipc_namespace {
 | 
				
			||||||
 | 
						struct kref	kref;
 | 
				
			||||||
 | 
						struct ipc_ids	*ids[3];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int		sem_ctls[4];
 | 
				
			||||||
 | 
						int		used_sems;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int		msg_ctlmax;
 | 
				
			||||||
 | 
						int		msg_ctlmnb;
 | 
				
			||||||
 | 
						int		msg_ctlmni;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t		shm_ctlmax;
 | 
				
			||||||
 | 
						size_t		shm_ctlall;
 | 
				
			||||||
 | 
						int		shm_ctlmni;
 | 
				
			||||||
 | 
						int		shm_tot;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct ipc_namespace init_ipc_ns;
 | 
				
			||||||
 | 
					extern void free_ipc_ns(struct kref *kref);
 | 
				
			||||||
 | 
					extern int copy_ipcs(unsigned long flags, struct task_struct *tsk);
 | 
				
			||||||
 | 
					extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (ns)
 | 
				
			||||||
 | 
							kref_get(&ns->kref);
 | 
				
			||||||
 | 
						return ns;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void put_ipc_ns(struct ipc_namespace *ns)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						kref_put(&ns->kref, free_ipc_ns);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __KERNEL__ */
 | 
					#endif /* __KERNEL__ */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _LINUX_IPC_H */
 | 
					#endif /* _LINUX_IPC_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct namespace;
 | 
					struct namespace;
 | 
				
			||||||
struct uts_namespace;
 | 
					struct uts_namespace;
 | 
				
			||||||
 | 
					struct ipc_namespace;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * A structure to contain pointers to all per-process
 | 
					 * A structure to contain pointers to all per-process
 | 
				
			||||||
| 
						 | 
					@ -23,6 +24,7 @@ struct nsproxy {
 | 
				
			||||||
	atomic_t count;
 | 
						atomic_t count;
 | 
				
			||||||
	spinlock_t nslock;
 | 
						spinlock_t nslock;
 | 
				
			||||||
	struct uts_namespace *uts_ns;
 | 
						struct uts_namespace *uts_ns;
 | 
				
			||||||
 | 
						struct ipc_namespace *ipc_ns;
 | 
				
			||||||
	struct namespace *namespace;
 | 
						struct namespace *namespace;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
extern struct nsproxy init_nsproxy;
 | 
					extern struct nsproxy init_nsproxy;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@
 | 
				
			||||||
#define CLONE_CHILD_SETTID	0x01000000	/* set the TID in the child */
 | 
					#define CLONE_CHILD_SETTID	0x01000000	/* set the TID in the child */
 | 
				
			||||||
#define CLONE_STOPPED		0x02000000	/* Start in stopped state */
 | 
					#define CLONE_STOPPED		0x02000000	/* Start in stopped state */
 | 
				
			||||||
#define CLONE_NEWUTS		0x04000000	/* New utsname group? */
 | 
					#define CLONE_NEWUTS		0x04000000	/* New utsname group? */
 | 
				
			||||||
 | 
					#define CLONE_NEWIPC		0x08000000	/* New ipcs */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Scheduling policies
 | 
					 * Scheduling policies
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,6 +115,15 @@ config SYSVIPC
 | 
				
			||||||
	  section 6.4 of the Linux Programmer's Guide, available from
 | 
						  section 6.4 of the Linux Programmer's Guide, available from
 | 
				
			||||||
	  <http://www.tldp.org/guides.html>.
 | 
						  <http://www.tldp.org/guides.html>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config IPC_NS
 | 
				
			||||||
 | 
						bool "IPC Namespaces"
 | 
				
			||||||
 | 
						depends on SYSVIPC
 | 
				
			||||||
 | 
						default n
 | 
				
			||||||
 | 
						help
 | 
				
			||||||
 | 
						  Support ipc namespaces.  This allows containers, i.e. virtual
 | 
				
			||||||
 | 
						  environments, to use ipc namespaces to provide different ipc
 | 
				
			||||||
 | 
						  objects for different servers.  If unsure, say N.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
config POSIX_MQUEUE
 | 
					config POSIX_MQUEUE
 | 
				
			||||||
	bool "POSIX Message Queues"
 | 
						bool "POSIX Message Queues"
 | 
				
			||||||
	depends on NET && EXPERIMENTAL
 | 
						depends on NET && EXPERIMENTAL
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1608,13 +1608,15 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
 | 
				
			||||||
	struct sem_undo_list *new_ulist = NULL;
 | 
						struct sem_undo_list *new_ulist = NULL;
 | 
				
			||||||
	struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL;
 | 
						struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL;
 | 
				
			||||||
	struct uts_namespace *uts, *new_uts = NULL;
 | 
						struct uts_namespace *uts, *new_uts = NULL;
 | 
				
			||||||
 | 
						struct ipc_namespace *ipc, *new_ipc = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	check_unshare_flags(&unshare_flags);
 | 
						check_unshare_flags(&unshare_flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Return -EINVAL for all unsupported flags */
 | 
						/* Return -EINVAL for all unsupported flags */
 | 
				
			||||||
	err = -EINVAL;
 | 
						err = -EINVAL;
 | 
				
			||||||
	if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
 | 
						if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
 | 
				
			||||||
				CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|CLONE_NEWUTS))
 | 
									CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
 | 
				
			||||||
 | 
									CLONE_NEWUTS|CLONE_NEWIPC))
 | 
				
			||||||
		goto bad_unshare_out;
 | 
							goto bad_unshare_out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((err = unshare_thread(unshare_flags)))
 | 
						if ((err = unshare_thread(unshare_flags)))
 | 
				
			||||||
| 
						 | 
					@ -1633,18 +1635,20 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
 | 
				
			||||||
		goto bad_unshare_cleanup_fd;
 | 
							goto bad_unshare_cleanup_fd;
 | 
				
			||||||
	if ((err = unshare_utsname(unshare_flags, &new_uts)))
 | 
						if ((err = unshare_utsname(unshare_flags, &new_uts)))
 | 
				
			||||||
		goto bad_unshare_cleanup_semundo;
 | 
							goto bad_unshare_cleanup_semundo;
 | 
				
			||||||
 | 
						if ((err = unshare_ipcs(unshare_flags, &new_ipc)))
 | 
				
			||||||
 | 
							goto bad_unshare_cleanup_uts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (new_ns || new_uts) {
 | 
						if (new_ns || new_uts || new_ipc) {
 | 
				
			||||||
		old_nsproxy = current->nsproxy;
 | 
							old_nsproxy = current->nsproxy;
 | 
				
			||||||
		new_nsproxy = dup_namespaces(old_nsproxy);
 | 
							new_nsproxy = dup_namespaces(old_nsproxy);
 | 
				
			||||||
		if (!new_nsproxy) {
 | 
							if (!new_nsproxy) {
 | 
				
			||||||
			err = -ENOMEM;
 | 
								err = -ENOMEM;
 | 
				
			||||||
			goto bad_unshare_cleanup_uts;
 | 
								goto bad_unshare_cleanup_ipc;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist ||
 | 
						if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist ||
 | 
				
			||||||
				new_uts) {
 | 
									new_uts || new_ipc) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		task_lock(current);
 | 
							task_lock(current);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1692,12 +1696,22 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
 | 
				
			||||||
			new_uts = uts;
 | 
								new_uts = uts;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (new_ipc) {
 | 
				
			||||||
 | 
								ipc = current->nsproxy->ipc_ns;
 | 
				
			||||||
 | 
								current->nsproxy->ipc_ns = new_ipc;
 | 
				
			||||||
 | 
								new_ipc = ipc;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		task_unlock(current);
 | 
							task_unlock(current);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (new_nsproxy)
 | 
						if (new_nsproxy)
 | 
				
			||||||
		put_nsproxy(new_nsproxy);
 | 
							put_nsproxy(new_nsproxy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					bad_unshare_cleanup_ipc:
 | 
				
			||||||
 | 
						if (new_ipc)
 | 
				
			||||||
 | 
							put_ipc_ns(new_ipc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bad_unshare_cleanup_uts:
 | 
					bad_unshare_cleanup_uts:
 | 
				
			||||||
	if (new_uts)
 | 
						if (new_uts)
 | 
				
			||||||
		put_uts_ns(new_uts);
 | 
							put_uts_ns(new_uts);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,10 @@
 | 
				
			||||||
 *  modify it under the terms of the GNU General Public License as
 | 
					 *  modify it under the terms of the GNU General Public License as
 | 
				
			||||||
 *  published by the Free Software Foundation, version 2 of the
 | 
					 *  published by the Free Software Foundation, version 2 of the
 | 
				
			||||||
 *  License.
 | 
					 *  License.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 *  Jun 2006 - namespaces support
 | 
				
			||||||
 | 
					 *             OpenVZ, SWsoft Inc.
 | 
				
			||||||
 | 
					 *             Pavel Emelianov <xemul@openvz.org>
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/module.h>
 | 
					#include <linux/module.h>
 | 
				
			||||||
| 
						 | 
					@ -62,6 +66,8 @@ struct nsproxy *dup_namespaces(struct nsproxy *orig)
 | 
				
			||||||
			get_namespace(ns->namespace);
 | 
								get_namespace(ns->namespace);
 | 
				
			||||||
		if (ns->uts_ns)
 | 
							if (ns->uts_ns)
 | 
				
			||||||
			get_uts_ns(ns->uts_ns);
 | 
								get_uts_ns(ns->uts_ns);
 | 
				
			||||||
 | 
							if (ns->ipc_ns)
 | 
				
			||||||
 | 
								get_ipc_ns(ns->ipc_ns);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ns;
 | 
						return ns;
 | 
				
			||||||
| 
						 | 
					@ -82,7 +88,7 @@ int copy_namespaces(int flags, struct task_struct *tsk)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	get_nsproxy(old_ns);
 | 
						get_nsproxy(old_ns);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS)))
 | 
						if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	new_ns = clone_namespaces(old_ns);
 | 
						new_ns = clone_namespaces(old_ns);
 | 
				
			||||||
| 
						 | 
					@ -94,24 +100,31 @@ int copy_namespaces(int flags, struct task_struct *tsk)
 | 
				
			||||||
	tsk->nsproxy = new_ns;
 | 
						tsk->nsproxy = new_ns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = copy_namespace(flags, tsk);
 | 
						err = copy_namespace(flags, tsk);
 | 
				
			||||||
	if (err) {
 | 
						if (err)
 | 
				
			||||||
		tsk->nsproxy = old_ns;
 | 
							goto out_ns;
 | 
				
			||||||
		put_nsproxy(new_ns);
 | 
					 | 
				
			||||||
		goto out;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = copy_utsname(flags, tsk);
 | 
						err = copy_utsname(flags, tsk);
 | 
				
			||||||
	if (err) {
 | 
						if (err)
 | 
				
			||||||
		if (new_ns->namespace)
 | 
							goto out_uts;
 | 
				
			||||||
			put_namespace(new_ns->namespace);
 | 
					
 | 
				
			||||||
		tsk->nsproxy = old_ns;
 | 
						err = copy_ipcs(flags, tsk);
 | 
				
			||||||
		put_nsproxy(new_ns);
 | 
						if (err)
 | 
				
			||||||
		goto out;
 | 
							goto out_ipc;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
out:
 | 
					out:
 | 
				
			||||||
	put_nsproxy(old_ns);
 | 
						put_nsproxy(old_ns);
 | 
				
			||||||
	return err;
 | 
						return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out_ipc:
 | 
				
			||||||
 | 
						if (new_ns->uts_ns)
 | 
				
			||||||
 | 
							put_uts_ns(new_ns->uts_ns);
 | 
				
			||||||
 | 
					out_uts:
 | 
				
			||||||
 | 
						if (new_ns->namespace)
 | 
				
			||||||
 | 
							put_namespace(new_ns->namespace);
 | 
				
			||||||
 | 
					out_ns:
 | 
				
			||||||
 | 
						tsk->nsproxy = old_ns;
 | 
				
			||||||
 | 
						put_nsproxy(new_ns);
 | 
				
			||||||
 | 
						goto out;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void free_nsproxy(struct nsproxy *ns)
 | 
					void free_nsproxy(struct nsproxy *ns)
 | 
				
			||||||
| 
						 | 
					@ -120,5 +133,7 @@ void free_nsproxy(struct nsproxy *ns)
 | 
				
			||||||
			put_namespace(ns->namespace);
 | 
								put_namespace(ns->namespace);
 | 
				
			||||||
		if (ns->uts_ns)
 | 
							if (ns->uts_ns)
 | 
				
			||||||
			put_uts_ns(ns->uts_ns);
 | 
								put_uts_ns(ns->uts_ns);
 | 
				
			||||||
 | 
							if (ns->ipc_ns)
 | 
				
			||||||
 | 
								put_ipc_ns(ns->ipc_ns);
 | 
				
			||||||
		kfree(ns);
 | 
							kfree(ns);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue