Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73ea4130 authored by Kirill Korotaev's avatar Kirill Korotaev Committed by Linus Torvalds
Browse files

[PATCH] IPC namespace - utils



This patch adds basic IPC namespace functionality to
IPC utils:
- init_ipc_ns
- copy/clone/unshare/free IPC ns
- /proc preparations

Signed-off-by: default avatarPavel Emelianov <xemul@openvz.org>
Signed-off-by: default avatarKirill Korotaev <dev@openvz.org>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Cedric Le Goater <clg@fr.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 25b21cb2
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#include <linux/irqflags.h>
#include <linux/utsname.h>
#include <linux/lockdep.h>
#include <linux/ipc.h>

#define INIT_FDTABLE \
{							\
@@ -74,8 +75,8 @@ extern struct nsproxy init_nsproxy;
	.count		= ATOMIC_INIT(1),				\
	.nslock		= SPIN_LOCK_UNLOCKED,				\
	.uts_ns		= &init_uts_ns,					\
	.ipc_ns		= &init_ipc_ns,					\
	.namespace	= NULL,						\
	INIT_IPC_NS(ipc_ns)						\
}

#define INIT_SIGHAND(sighand) {						\
+18 −0
Original line number Diff line number Diff line
@@ -88,20 +88,38 @@ struct ipc_namespace {
};

extern struct ipc_namespace init_ipc_ns;

#ifdef CONFIG_SYSVIPC
#define INIT_IPC_NS(ns)		.ns		= &init_ipc_ns,
#else
#define INIT_IPC_NS(ns)
#endif

#ifdef CONFIG_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);
#else
static inline int copy_ipcs(unsigned long flags, struct task_struct *tsk)
{
	return 0;
}
#endif

static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
{
#ifdef CONFIG_IPC_NS
	if (ns)
		kref_get(&ns->kref);
#endif
	return ns;
}

static inline void put_ipc_ns(struct ipc_namespace *ns)
{
#ifdef CONFIG_IPC_NS
	kref_put(&ns->kref, free_ipc_ns);
#endif
}

#endif /* __KERNEL__ */
+122 −10
Original line number Diff line number Diff line
@@ -12,6 +12,9 @@
 *            Mingming Cao <cmm@us.ibm.com>
 * Mar 2006 - support for audit of ipc object properties
 *            Dustin Kirkland <dustin.kirkland@us.ibm.com>
 * Jun 2006 - namespaces ssupport
 *            OpenVZ, SWsoft Inc.
 *            Pavel Emelianov <xemul@openvz.org>
 */

#include <linux/mm.h>
@@ -29,6 +32,7 @@
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/audit.h>
#include <linux/nsproxy.h>

#include <asm/unistd.h>

@@ -37,10 +41,111 @@
struct ipc_proc_iface {
	const char *path;
	const char *header;
	struct ipc_ids *ids;
	int ids;
	int (*show)(struct seq_file *, void *);
};

struct ipc_namespace init_ipc_ns = {
	.kref = {
		.refcount	= ATOMIC_INIT(2),
	},
};

#ifdef CONFIG_IPC_NS
static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)
{
	int err;
	struct ipc_namespace *ns;

	err = -ENOMEM;
	ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
	if (ns == NULL)
		goto err_mem;

	err = sem_init_ns(ns);
	if (err)
		goto err_sem;
	err = msg_init_ns(ns);
	if (err)
		goto err_msg;
	err = shm_init_ns(ns);
	if (err)
		goto err_shm;

	kref_init(&ns->kref);
	return ns;

err_shm:
	msg_exit_ns(ns);
err_msg:
	sem_exit_ns(ns);
err_sem:
	kfree(ns);
err_mem:
	return ERR_PTR(err);
}

int unshare_ipcs(unsigned long unshare_flags, struct ipc_namespace **new_ipc)
{
	struct ipc_namespace *new;

	if (unshare_flags & CLONE_NEWIPC) {
		if (!capable(CAP_SYS_ADMIN))
			return -EPERM;

		new = clone_ipc_ns(current->nsproxy->ipc_ns);
		if (IS_ERR(new))
			return PTR_ERR(new);

		*new_ipc = new;
	}

	return 0;
}

int copy_ipcs(unsigned long flags, struct task_struct *tsk)
{
	struct ipc_namespace *old_ns = tsk->nsproxy->ipc_ns;
	struct ipc_namespace *new_ns;
	int err = 0;

	if (!old_ns)
		return 0;

	get_ipc_ns(old_ns);

	if (!(flags & CLONE_NEWIPC))
		return 0;

	if (!capable(CAP_SYS_ADMIN)) {
		err = -EPERM;
		goto out;
	}

	new_ns = clone_ipc_ns(old_ns);
	if (!new_ns) {
		err = -ENOMEM;
		goto out;
	}

	tsk->nsproxy->ipc_ns = new_ns;
out:
	put_ipc_ns(old_ns);
	return err;
}

void free_ipc_ns(struct kref *kref)
{
	struct ipc_namespace *ns;

	ns = container_of(kref, struct ipc_namespace, kref);
	sem_exit_ns(ns);
	msg_exit_ns(ns);
	shm_exit_ns(ns);
	kfree(ns);
}
#endif

/**
 *	ipc_init	-	initialise IPC subsystem
 *
@@ -67,7 +172,7 @@ __initcall(ipc_init);
 *	array itself. 
 */
 
void __init ipc_init_ids(struct ipc_ids* ids, int size)
void __ipc_init ipc_init_ids(struct ipc_ids* ids, int size)
{
	int i;

@@ -110,8 +215,7 @@ static struct file_operations sysvipc_proc_fops;
 *	@show: show routine.
 */
void __init ipc_init_proc_interface(const char *path, const char *header,
				    struct ipc_ids *ids,
				    int (*show)(struct seq_file *, void *))
		int ids, int (*show)(struct seq_file *, void *))
{
	struct proc_dir_entry *pde;
	struct ipc_proc_iface *iface;
@@ -635,6 +739,9 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
	struct ipc_proc_iface *iface = s->private;
	struct kern_ipc_perm *ipc = it;
	loff_t p;
	struct ipc_ids *ids;

	ids = current->nsproxy->ipc_ns->ids[iface->ids];

	/* If we had an ipc id locked before, unlock it */
	if (ipc && ipc != SEQ_START_TOKEN)
@@ -644,8 +751,8 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
	 * p = *pos - 1 (because id 0 starts at position 1)
	 *          + 1 (because we increment the position by one)
	 */
	for (p = *pos; p <= iface->ids->max_id; p++) {
		if ((ipc = ipc_lock(iface->ids, p)) != NULL) {
	for (p = *pos; p <= ids->max_id; p++) {
		if ((ipc = ipc_lock(ids, p)) != NULL) {
			*pos = p + 1;
			return ipc;
		}
@@ -664,12 +771,15 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
	struct ipc_proc_iface *iface = s->private;
	struct kern_ipc_perm *ipc;
	loff_t p;
	struct ipc_ids *ids;

	ids = current->nsproxy->ipc_ns->ids[iface->ids];

	/*
	 * Take the lock - this will be released by the corresponding
	 * call to stop().
	 */
	mutex_lock(&iface->ids->mutex);
	mutex_lock(&ids->mutex);

	/* pos < 0 is invalid */
	if (*pos < 0)
@@ -680,8 +790,8 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
		return SEQ_START_TOKEN;

	/* Find the (pos-1)th ipc */
	for (p = *pos - 1; p <= iface->ids->max_id; p++) {
		if ((ipc = ipc_lock(iface->ids, p)) != NULL) {
	for (p = *pos - 1; p <= ids->max_id; p++) {
		if ((ipc = ipc_lock(ids, p)) != NULL) {
			*pos = p + 1;
			return ipc;
		}
@@ -693,13 +803,15 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it)
{
	struct kern_ipc_perm *ipc = it;
	struct ipc_proc_iface *iface = s->private;
	struct ipc_ids *ids;

	/* If we had a locked segment, release it */
	if (ipc && ipc != SEQ_START_TOKEN)
		ipc_unlock(ipc);

	ids = current->nsproxy->ipc_ns->ids[iface->ids];
	/* Release the lock we took in start() */
	mutex_unlock(&iface->ids->mutex);
	mutex_unlock(&ids->mutex);
}

static int sysvipc_proc_show(struct seq_file *s, void *it)
+21 −3
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@
 * Copyright (C) 1999 Christoph Rohland
 *
 * ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com>
 * namespaces support.      2006 OpenVZ, SWsoft Inc.
 *                               Pavel Emelianov <xemul@openvz.org>
 */

#ifndef _IPC_UTIL_H
@@ -15,6 +17,14 @@ void sem_init (void);
void msg_init (void);
void shm_init (void);

int sem_init_ns(struct ipc_namespace *ns);
int msg_init_ns(struct ipc_namespace *ns);
int shm_init_ns(struct ipc_namespace *ns);

void sem_exit_ns(struct ipc_namespace *ns);
void msg_exit_ns(struct ipc_namespace *ns);
void shm_exit_ns(struct ipc_namespace *ns);

struct ipc_id_ary {
	int size;
	struct kern_ipc_perm *p[0];
@@ -31,15 +41,23 @@ struct ipc_ids {
};

struct seq_file;
void __init ipc_init_ids(struct ipc_ids* ids, int size);
#ifdef CONFIG_IPC_NS
#define __ipc_init
#else
#define __ipc_init	__init
#endif
void __ipc_init ipc_init_ids(struct ipc_ids *ids, int size);
#ifdef CONFIG_PROC_FS
void __init ipc_init_proc_interface(const char *path, const char *header,
				    struct ipc_ids *ids,
				    int (*show)(struct seq_file *, void *));
		int ids, int (*show)(struct seq_file *, void *));
#else
#define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
#endif

#define IPC_SEM_IDS	0
#define IPC_MSG_IDS	1
#define IPC_SHM_IDS	2

/* must be called with ids->mutex acquired.*/
int ipc_findkey(struct ipc_ids* ids, key_t key);
int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size);
+10 −0
Original line number Diff line number Diff line
@@ -1589,6 +1589,16 @@ static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **n
	return 0;
}

#ifndef CONFIG_IPC_NS
static inline int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns)
{
	if (flags & CLONE_NEWIPC)
		return -EINVAL;

	return 0;
}
#endif

/*
 * unshare allows a process to 'unshare' part of the process
 * context which was originally shared using clone.  copy_*