aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/init_task.h3
-rw-r--r--include/linux/ipc.h18
-rw-r--r--ipc/util.c132
-rw-r--r--ipc/util.h24
-rw-r--r--kernel/fork.c10
5 files changed, 173 insertions, 14 deletions
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index ceecf69dfa39..33c5daacc743 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -6,6 +6,7 @@
6#include <linux/irqflags.h> 6#include <linux/irqflags.h>
7#include <linux/utsname.h> 7#include <linux/utsname.h>
8#include <linux/lockdep.h> 8#include <linux/lockdep.h>
9#include <linux/ipc.h>
9 10
10#define INIT_FDTABLE \ 11#define INIT_FDTABLE \
11{ \ 12{ \
@@ -74,8 +75,8 @@ extern struct nsproxy init_nsproxy;
74 .count = ATOMIC_INIT(1), \ 75 .count = ATOMIC_INIT(1), \
75 .nslock = SPIN_LOCK_UNLOCKED, \ 76 .nslock = SPIN_LOCK_UNLOCKED, \
76 .uts_ns = &init_uts_ns, \ 77 .uts_ns = &init_uts_ns, \
77 .ipc_ns = &init_ipc_ns, \
78 .namespace = NULL, \ 78 .namespace = NULL, \
79 INIT_IPC_NS(ipc_ns) \
79} 80}
80 81
81#define INIT_SIGHAND(sighand) { \ 82#define INIT_SIGHAND(sighand) { \
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index 36027b10f283..d9e2b3f36c35 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -88,20 +88,38 @@ struct ipc_namespace {
88}; 88};
89 89
90extern struct ipc_namespace init_ipc_ns; 90extern struct ipc_namespace init_ipc_ns;
91
92#ifdef CONFIG_SYSVIPC
93#define INIT_IPC_NS(ns) .ns = &init_ipc_ns,
94#else
95#define INIT_IPC_NS(ns)
96#endif
97
98#ifdef CONFIG_IPC_NS
91extern void free_ipc_ns(struct kref *kref); 99extern void free_ipc_ns(struct kref *kref);
92extern int copy_ipcs(unsigned long flags, struct task_struct *tsk); 100extern int copy_ipcs(unsigned long flags, struct task_struct *tsk);
93extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns); 101extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns);
102#else
103static inline int copy_ipcs(unsigned long flags, struct task_struct *tsk)
104{
105 return 0;
106}
107#endif
94 108
95static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) 109static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
96{ 110{
111#ifdef CONFIG_IPC_NS
97 if (ns) 112 if (ns)
98 kref_get(&ns->kref); 113 kref_get(&ns->kref);
114#endif
99 return ns; 115 return ns;
100} 116}
101 117
102static inline void put_ipc_ns(struct ipc_namespace *ns) 118static inline void put_ipc_ns(struct ipc_namespace *ns)
103{ 119{
120#ifdef CONFIG_IPC_NS
104 kref_put(&ns->kref, free_ipc_ns); 121 kref_put(&ns->kref, free_ipc_ns);
122#endif
105} 123}
106 124
107#endif /* __KERNEL__ */ 125#endif /* __KERNEL__ */
diff --git a/ipc/util.c b/ipc/util.c
index 67b6d178db6e..42479e4eec59 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -12,6 +12,9 @@
12 * Mingming Cao <cmm@us.ibm.com> 12 * Mingming Cao <cmm@us.ibm.com>
13 * Mar 2006 - support for audit of ipc object properties 13 * Mar 2006 - support for audit of ipc object properties
14 * Dustin Kirkland <dustin.kirkland@us.ibm.com> 14 * Dustin Kirkland <dustin.kirkland@us.ibm.com>
15 * Jun 2006 - namespaces ssupport
16 * OpenVZ, SWsoft Inc.
17 * Pavel Emelianov <xemul@openvz.org>
15 */ 18 */
16 19
17#include <linux/mm.h> 20#include <linux/mm.h>
@@ -29,6 +32,7 @@
29#include <linux/seq_file.h> 32#include <linux/seq_file.h>
30#include <linux/proc_fs.h> 33#include <linux/proc_fs.h>
31#include <linux/audit.h> 34#include <linux/audit.h>
35#include <linux/nsproxy.h>
32 36
33#include <asm/unistd.h> 37#include <asm/unistd.h>
34 38
@@ -37,10 +41,111 @@
37struct ipc_proc_iface { 41struct ipc_proc_iface {
38 const char *path; 42 const char *path;
39 const char *header; 43 const char *header;
40 struct ipc_ids *ids; 44 int ids;
41 int (*show)(struct seq_file *, void *); 45 int (*show)(struct seq_file *, void *);
42}; 46};
43 47
48struct ipc_namespace init_ipc_ns = {
49 .kref = {
50 .refcount = ATOMIC_INIT(2),
51 },
52};
53
54#ifdef CONFIG_IPC_NS
55static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)
56{
57 int err;
58 struct ipc_namespace *ns;
59
60 err = -ENOMEM;
61 ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
62 if (ns == NULL)
63 goto err_mem;
64
65 err = sem_init_ns(ns);
66 if (err)
67 goto err_sem;
68 err = msg_init_ns(ns);
69 if (err)
70 goto err_msg;
71 err = shm_init_ns(ns);
72 if (err)
73 goto err_shm;
74
75 kref_init(&ns->kref);
76 return ns;
77
78err_shm:
79 msg_exit_ns(ns);
80err_msg:
81 sem_exit_ns(ns);
82err_sem:
83 kfree(ns);
84err_mem:
85 return ERR_PTR(err);
86}
87
88int unshare_ipcs(unsigned long unshare_flags, struct ipc_namespace **new_ipc)
89{
90 struct ipc_namespace *new;
91
92 if (unshare_flags & CLONE_NEWIPC) {
93 if (!capable(CAP_SYS_ADMIN))
94 return -EPERM;
95
96 new = clone_ipc_ns(current->nsproxy->ipc_ns);
97 if (IS_ERR(new))
98 return PTR_ERR(new);
99
100 *new_ipc = new;
101 }
102
103 return 0;
104}
105
106int copy_ipcs(unsigned long flags, struct task_struct *tsk)
107{
108 struct ipc_namespace *old_ns = tsk->nsproxy->ipc_ns;
109 struct ipc_namespace *new_ns;
110 int err = 0;
111
112 if (!old_ns)
113 return 0;
114
115 get_ipc_ns(old_ns);
116
117 if (!(flags & CLONE_NEWIPC))
118 return 0;
119
120 if (!capable(CAP_SYS_ADMIN)) {
121 err = -EPERM;
122 goto out;
123 }
124
125 new_ns = clone_ipc_ns(old_ns);
126 if (!new_ns) {
127 err = -ENOMEM;
128 goto out;
129 }
130
131 tsk->nsproxy->ipc_ns = new_ns;
132out:
133 put_ipc_ns(old_ns);
134 return err;
135}
136
137void free_ipc_ns(struct kref *kref)
138{
139 struct ipc_namespace *ns;
140
141 ns = container_of(kref, struct ipc_namespace, kref);
142 sem_exit_ns(ns);
143 msg_exit_ns(ns);
144 shm_exit_ns(ns);
145 kfree(ns);
146}
147#endif
148
44/** 149/**
45 * ipc_init - initialise IPC subsystem 150 * ipc_init - initialise IPC subsystem
46 * 151 *
@@ -67,7 +172,7 @@ __initcall(ipc_init);
67 * array itself. 172 * array itself.
68 */ 173 */
69 174
70void __init ipc_init_ids(struct ipc_ids* ids, int size) 175void __ipc_init ipc_init_ids(struct ipc_ids* ids, int size)
71{ 176{
72 int i; 177 int i;
73 178
@@ -110,8 +215,7 @@ static struct file_operations sysvipc_proc_fops;
110 * @show: show routine. 215 * @show: show routine.
111 */ 216 */
112void __init ipc_init_proc_interface(const char *path, const char *header, 217void __init ipc_init_proc_interface(const char *path, const char *header,
113 struct ipc_ids *ids, 218 int ids, int (*show)(struct seq_file *, void *))
114 int (*show)(struct seq_file *, void *))
115{ 219{
116 struct proc_dir_entry *pde; 220 struct proc_dir_entry *pde;
117 struct ipc_proc_iface *iface; 221 struct ipc_proc_iface *iface;
@@ -635,6 +739,9 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
635 struct ipc_proc_iface *iface = s->private; 739 struct ipc_proc_iface *iface = s->private;
636 struct kern_ipc_perm *ipc = it; 740 struct kern_ipc_perm *ipc = it;
637 loff_t p; 741 loff_t p;
742 struct ipc_ids *ids;
743
744 ids = current->nsproxy->ipc_ns->ids[iface->ids];
638 745
639 /* If we had an ipc id locked before, unlock it */ 746 /* If we had an ipc id locked before, unlock it */
640 if (ipc && ipc != SEQ_START_TOKEN) 747 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 * p = *pos - 1 (because id 0 starts at position 1) 751 * p = *pos - 1 (because id 0 starts at position 1)
645 * + 1 (because we increment the position by one) 752 * + 1 (because we increment the position by one)
646 */ 753 */
647 for (p = *pos; p <= iface->ids->max_id; p++) { 754 for (p = *pos; p <= ids->max_id; p++) {
648 if ((ipc = ipc_lock(iface->ids, p)) != NULL) { 755 if ((ipc = ipc_lock(ids, p)) != NULL) {
649 *pos = p + 1; 756 *pos = p + 1;
650 return ipc; 757 return ipc;
651 } 758 }
@@ -664,12 +771,15 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
664 struct ipc_proc_iface *iface = s->private; 771 struct ipc_proc_iface *iface = s->private;
665 struct kern_ipc_perm *ipc; 772 struct kern_ipc_perm *ipc;
666 loff_t p; 773 loff_t p;
774 struct ipc_ids *ids;
775
776 ids = current->nsproxy->ipc_ns->ids[iface->ids];
667 777
668 /* 778 /*
669 * Take the lock - this will be released by the corresponding 779 * Take the lock - this will be released by the corresponding
670 * call to stop(). 780 * call to stop().
671 */ 781 */
672 mutex_lock(&iface->ids->mutex); 782 mutex_lock(&ids->mutex);
673 783
674 /* pos < 0 is invalid */ 784 /* pos < 0 is invalid */
675 if (*pos < 0) 785 if (*pos < 0)
@@ -680,8 +790,8 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
680 return SEQ_START_TOKEN; 790 return SEQ_START_TOKEN;
681 791
682 /* Find the (pos-1)th ipc */ 792 /* Find the (pos-1)th ipc */
683 for (p = *pos - 1; p <= iface->ids->max_id; p++) { 793 for (p = *pos - 1; p <= ids->max_id; p++) {
684 if ((ipc = ipc_lock(iface->ids, p)) != NULL) { 794 if ((ipc = ipc_lock(ids, p)) != NULL) {
685 *pos = p + 1; 795 *pos = p + 1;
686 return ipc; 796 return ipc;
687 } 797 }
@@ -693,13 +803,15 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it)
693{ 803{
694 struct kern_ipc_perm *ipc = it; 804 struct kern_ipc_perm *ipc = it;
695 struct ipc_proc_iface *iface = s->private; 805 struct ipc_proc_iface *iface = s->private;
806 struct ipc_ids *ids;
696 807
697 /* If we had a locked segment, release it */ 808 /* If we had a locked segment, release it */
698 if (ipc && ipc != SEQ_START_TOKEN) 809 if (ipc && ipc != SEQ_START_TOKEN)
699 ipc_unlock(ipc); 810 ipc_unlock(ipc);
700 811
812 ids = current->nsproxy->ipc_ns->ids[iface->ids];
701 /* Release the lock we took in start() */ 813 /* Release the lock we took in start() */
702 mutex_unlock(&iface->ids->mutex); 814 mutex_unlock(&ids->mutex);
703} 815}
704 816
705static int sysvipc_proc_show(struct seq_file *s, void *it) 817static int sysvipc_proc_show(struct seq_file *s, void *it)
diff --git a/ipc/util.h b/ipc/util.h
index 0181553d31d8..c8fd6b9d77b5 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -3,6 +3,8 @@
3 * Copyright (C) 1999 Christoph Rohland 3 * Copyright (C) 1999 Christoph Rohland
4 * 4 *
5 * ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com> 5 * ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com>
6 * namespaces support. 2006 OpenVZ, SWsoft Inc.
7 * Pavel Emelianov <xemul@openvz.org>
6 */ 8 */
7 9
8#ifndef _IPC_UTIL_H 10#ifndef _IPC_UTIL_H
@@ -15,6 +17,14 @@ void sem_init (void);
15void msg_init (void); 17void msg_init (void);
16void shm_init (void); 18void shm_init (void);
17 19
20int sem_init_ns(struct ipc_namespace *ns);
21int msg_init_ns(struct ipc_namespace *ns);
22int shm_init_ns(struct ipc_namespace *ns);
23
24void sem_exit_ns(struct ipc_namespace *ns);
25void msg_exit_ns(struct ipc_namespace *ns);
26void shm_exit_ns(struct ipc_namespace *ns);
27
18struct ipc_id_ary { 28struct ipc_id_ary {
19 int size; 29 int size;
20 struct kern_ipc_perm *p[0]; 30 struct kern_ipc_perm *p[0];
@@ -31,15 +41,23 @@ struct ipc_ids {
31}; 41};
32 42
33struct seq_file; 43struct seq_file;
34void __init ipc_init_ids(struct ipc_ids* ids, int size); 44#ifdef CONFIG_IPC_NS
45#define __ipc_init
46#else
47#define __ipc_init __init
48#endif
49void __ipc_init ipc_init_ids(struct ipc_ids *ids, int size);
35#ifdef CONFIG_PROC_FS 50#ifdef CONFIG_PROC_FS
36void __init ipc_init_proc_interface(const char *path, const char *header, 51void __init ipc_init_proc_interface(const char *path, const char *header,
37 struct ipc_ids *ids, 52 int ids, int (*show)(struct seq_file *, void *));
38 int (*show)(struct seq_file *, void *));
39#else 53#else
40#define ipc_init_proc_interface(path, header, ids, show) do {} while (0) 54#define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
41#endif 55#endif
42 56
57#define IPC_SEM_IDS 0
58#define IPC_MSG_IDS 1
59#define IPC_SHM_IDS 2
60
43/* must be called with ids->mutex acquired.*/ 61/* must be called with ids->mutex acquired.*/
44int ipc_findkey(struct ipc_ids* ids, key_t key); 62int ipc_findkey(struct ipc_ids* ids, key_t key);
45int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size); 63int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size);
diff --git a/kernel/fork.c b/kernel/fork.c
index d6cc56558507..7dc6140baac6 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1589,6 +1589,16 @@ static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **n
1589 return 0; 1589 return 0;
1590} 1590}
1591 1591
1592#ifndef CONFIG_IPC_NS
1593static inline int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns)
1594{
1595 if (flags & CLONE_NEWIPC)
1596 return -EINVAL;
1597
1598 return 0;
1599}
1600#endif
1601
1592/* 1602/*
1593 * unshare allows a process to 'unshare' part of the process 1603 * unshare allows a process to 'unshare' part of the process
1594 * context which was originally shared using clone. copy_* 1604 * context which was originally shared using clone. copy_*