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

[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
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <linux/irqflags.h> #include <linux/irqflags.h>
#include <linux/utsname.h> #include <linux/utsname.h>
#include <linux/lockdep.h> #include <linux/lockdep.h>
#include <linux/ipc.h>
#define INIT_FDTABLE \ #define INIT_FDTABLE \
{ \ { \
...@@ -74,8 +75,8 @@ extern struct nsproxy init_nsproxy; ...@@ -74,8 +75,8 @@ 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, \
INIT_IPC_NS(ipc_ns) \
} }
#define INIT_SIGHAND(sighand) { \ #define INIT_SIGHAND(sighand) { \
......
...@@ -88,20 +88,38 @@ struct ipc_namespace { ...@@ -88,20 +88,38 @@ struct ipc_namespace {
}; };
extern struct ipc_namespace init_ipc_ns; 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 void free_ipc_ns(struct kref *kref);
extern int copy_ipcs(unsigned long flags, struct task_struct *tsk); extern int copy_ipcs(unsigned long flags, struct task_struct *tsk);
extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns); 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) static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
{ {
#ifdef CONFIG_IPC_NS
if (ns) if (ns)
kref_get(&ns->kref); kref_get(&ns->kref);
#endif
return ns; return ns;
} }
static inline void put_ipc_ns(struct ipc_namespace *ns) static inline void put_ipc_ns(struct ipc_namespace *ns)
{ {
#ifdef CONFIG_IPC_NS
kref_put(&ns->kref, free_ipc_ns); kref_put(&ns->kref, free_ipc_ns);
#endif
} }
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
* Mingming Cao <cmm@us.ibm.com> * Mingming Cao <cmm@us.ibm.com>
* Mar 2006 - support for audit of ipc object properties * Mar 2006 - support for audit of ipc object properties
* Dustin Kirkland <dustin.kirkland@us.ibm.com> * Dustin Kirkland <dustin.kirkland@us.ibm.com>
* Jun 2006 - namespaces ssupport
* OpenVZ, SWsoft Inc.
* Pavel Emelianov <xemul@openvz.org>
*/ */
#include <linux/mm.h> #include <linux/mm.h>
...@@ -29,6 +32,7 @@ ...@@ -29,6 +32,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/audit.h> #include <linux/audit.h>
#include <linux/nsproxy.h>
#include <asm/unistd.h> #include <asm/unistd.h>
...@@ -37,10 +41,111 @@ ...@@ -37,10 +41,111 @@
struct ipc_proc_iface { struct ipc_proc_iface {
const char *path; const char *path;
const char *header; const char *header;
struct ipc_ids *ids; int ids;
int (*show)(struct seq_file *, void *); 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 * ipc_init - initialise IPC subsystem
* *
...@@ -67,7 +172,7 @@ __initcall(ipc_init); ...@@ -67,7 +172,7 @@ __initcall(ipc_init);
* array itself. * 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; int i;
...@@ -110,8 +215,7 @@ static struct file_operations sysvipc_proc_fops; ...@@ -110,8 +215,7 @@ static struct file_operations sysvipc_proc_fops;
* @show: show routine. * @show: show routine.
*/ */
void __init ipc_init_proc_interface(const char *path, const char *header, void __init ipc_init_proc_interface(const char *path, const char *header,
struct ipc_ids *ids, int ids, int (*show)(struct seq_file *, void *))
int (*show)(struct seq_file *, void *))
{ {
struct proc_dir_entry *pde; struct proc_dir_entry *pde;
struct ipc_proc_iface *iface; struct ipc_proc_iface *iface;
...@@ -635,6 +739,9 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) ...@@ -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 ipc_proc_iface *iface = s->private;
struct kern_ipc_perm *ipc = it; struct kern_ipc_perm *ipc = it;
loff_t p; 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 we had an ipc id locked before, unlock it */
if (ipc && ipc != SEQ_START_TOKEN) if (ipc && ipc != SEQ_START_TOKEN)
...@@ -644,8 +751,8 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) ...@@ -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) * p = *pos - 1 (because id 0 starts at position 1)
* + 1 (because we increment the position by one) * + 1 (because we increment the position by one)
*/ */
for (p = *pos; p <= iface->ids->max_id; p++) { for (p = *pos; p <= ids->max_id; p++) {
if ((ipc = ipc_lock(iface->ids, p)) != NULL) { if ((ipc = ipc_lock(ids, p)) != NULL) {
*pos = p + 1; *pos = p + 1;
return ipc; return ipc;
} }
...@@ -664,12 +771,15 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) ...@@ -664,12 +771,15 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
struct ipc_proc_iface *iface = s->private; struct ipc_proc_iface *iface = s->private;
struct kern_ipc_perm *ipc; struct kern_ipc_perm *ipc;
loff_t p; 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 * Take the lock - this will be released by the corresponding
* call to stop(). * call to stop().
*/ */
mutex_lock(&iface->ids->mutex); mutex_lock(&ids->mutex);
/* pos < 0 is invalid */ /* pos < 0 is invalid */
if (*pos < 0) if (*pos < 0)
...@@ -680,8 +790,8 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) ...@@ -680,8 +790,8 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
return SEQ_START_TOKEN; return SEQ_START_TOKEN;
/* Find the (pos-1)th ipc */ /* Find the (pos-1)th ipc */
for (p = *pos - 1; p <= iface->ids->max_id; p++) { for (p = *pos - 1; p <= ids->max_id; p++) {
if ((ipc = ipc_lock(iface->ids, p)) != NULL) { if ((ipc = ipc_lock(ids, p)) != NULL) {
*pos = p + 1; *pos = p + 1;
return ipc; return ipc;
} }
...@@ -693,13 +803,15 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it) ...@@ -693,13 +803,15 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it)
{ {
struct kern_ipc_perm *ipc = it; struct kern_ipc_perm *ipc = it;
struct ipc_proc_iface *iface = s->private; struct ipc_proc_iface *iface = s->private;
struct ipc_ids *ids;
/* If we had a locked segment, release it */ /* If we had a locked segment, release it */
if (ipc && ipc != SEQ_START_TOKEN) if (ipc && ipc != SEQ_START_TOKEN)
ipc_unlock(ipc); ipc_unlock(ipc);
ids = current->nsproxy->ipc_ns->ids[iface->ids];
/* Release the lock we took in start() */ /* 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) static int sysvipc_proc_show(struct seq_file *s, void *it)
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
* Copyright (C) 1999 Christoph Rohland * Copyright (C) 1999 Christoph Rohland
* *
* ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com> * 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 #ifndef _IPC_UTIL_H
...@@ -15,6 +17,14 @@ void sem_init (void); ...@@ -15,6 +17,14 @@ void sem_init (void);
void msg_init (void); void msg_init (void);
void shm_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 { struct ipc_id_ary {
int size; int size;
struct kern_ipc_perm *p[0]; struct kern_ipc_perm *p[0];
...@@ -31,15 +41,23 @@ struct ipc_ids { ...@@ -31,15 +41,23 @@ struct ipc_ids {
}; };
struct seq_file; 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 #ifdef CONFIG_PROC_FS
void __init ipc_init_proc_interface(const char *path, const char *header, void __init ipc_init_proc_interface(const char *path, const char *header,
struct ipc_ids *ids, int ids, int (*show)(struct seq_file *, void *));
int (*show)(struct seq_file *, void *));
#else #else
#define ipc_init_proc_interface(path, header, ids, show) do {} while (0) #define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
#endif #endif
#define IPC_SEM_IDS 0
#define IPC_MSG_IDS 1
#define IPC_SHM_IDS 2
/* must be called with ids->mutex acquired.*/ /* must be called with ids->mutex acquired.*/
int ipc_findkey(struct ipc_ids* ids, key_t key); int ipc_findkey(struct ipc_ids* ids, key_t key);
int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size); int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size);
......
...@@ -1589,6 +1589,16 @@ static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **n ...@@ -1589,6 +1589,16 @@ static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **n
return 0; 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 * unshare allows a process to 'unshare' part of the process
* context which was originally shared using clone. copy_* * context which was originally shared using clone. copy_*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment