aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /ipc
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'ipc')
-rw-r--r--ipc/compat.c6
-rw-r--r--ipc/compat_mq.c5
-rw-r--r--ipc/mqueue.c21
-rw-r--r--ipc/msg.c12
-rw-r--r--ipc/msgutil.c1
-rw-r--r--ipc/namespace.c53
-rw-r--r--ipc/sem.c12
-rw-r--r--ipc/shm.c79
-rw-r--r--ipc/util.c28
-rw-r--r--ipc/util.h5
10 files changed, 162 insertions, 60 deletions
diff --git a/ipc/compat.c b/ipc/compat.c
index 9dc2c7d3c9e6..845a28738d3a 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -241,6 +241,8 @@ long compat_sys_semctl(int first, int second, int third, void __user *uptr)
241 struct semid64_ds __user *up64; 241 struct semid64_ds __user *up64;
242 int version = compat_ipc_parse_version(&third); 242 int version = compat_ipc_parse_version(&third);
243 243
244 memset(&s64, 0, sizeof(s64));
245
244 if (!uptr) 246 if (!uptr)
245 return -EINVAL; 247 return -EINVAL;
246 if (get_user(pad, (u32 __user *) uptr)) 248 if (get_user(pad, (u32 __user *) uptr))
@@ -421,6 +423,8 @@ long compat_sys_msgctl(int first, int second, void __user *uptr)
421 int version = compat_ipc_parse_version(&second); 423 int version = compat_ipc_parse_version(&second);
422 void __user *p; 424 void __user *p;
423 425
426 memset(&m64, 0, sizeof(m64));
427
424 switch (second & (~IPC_64)) { 428 switch (second & (~IPC_64)) {
425 case IPC_INFO: 429 case IPC_INFO:
426 case IPC_RMID: 430 case IPC_RMID:
@@ -594,6 +598,8 @@ long compat_sys_shmctl(int first, int second, void __user *uptr)
594 int err, err2; 598 int err, err2;
595 int version = compat_ipc_parse_version(&second); 599 int version = compat_ipc_parse_version(&second);
596 600
601 memset(&s64, 0, sizeof(s64));
602
597 switch (second & (~IPC_64)) { 603 switch (second & (~IPC_64)) {
598 case IPC_RMID: 604 case IPC_RMID:
599 case SHM_LOCK: 605 case SHM_LOCK:
diff --git a/ipc/compat_mq.c b/ipc/compat_mq.c
index d8d1e9ff4e88..380ea4fe08e7 100644
--- a/ipc/compat_mq.c
+++ b/ipc/compat_mq.c
@@ -53,6 +53,9 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name,
53 void __user *p = NULL; 53 void __user *p = NULL;
54 if (u_attr && oflag & O_CREAT) { 54 if (u_attr && oflag & O_CREAT) {
55 struct mq_attr attr; 55 struct mq_attr attr;
56
57 memset(&attr, 0, sizeof(attr));
58
56 p = compat_alloc_user_space(sizeof(attr)); 59 p = compat_alloc_user_space(sizeof(attr));
57 if (get_compat_mq_attr(&attr, u_attr) || 60 if (get_compat_mq_attr(&attr, u_attr) ||
58 copy_to_user(p, &attr, sizeof(attr))) 61 copy_to_user(p, &attr, sizeof(attr)))
@@ -127,6 +130,8 @@ asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes,
127 struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p)); 130 struct mq_attr __user *p = compat_alloc_user_space(2 * sizeof(*p));
128 long ret; 131 long ret;
129 132
133 memset(&mqstat, 0, sizeof(mqstat));
134
130 if (u_mqstat) { 135 if (u_mqstat) {
131 if (get_compat_mq_attr(&mqstat, u_mqstat) || 136 if (get_compat_mq_attr(&mqstat, u_mqstat) ||
132 copy_to_user(p, &mqstat, sizeof(mqstat))) 137 copy_to_user(p, &mqstat, sizeof(mqstat)))
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index c60e519e2917..14fb6d67e6a3 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -116,6 +116,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
116 116
117 inode = new_inode(sb); 117 inode = new_inode(sb);
118 if (inode) { 118 if (inode) {
119 inode->i_ino = get_next_ino();
119 inode->i_mode = mode; 120 inode->i_mode = mode;
120 inode->i_uid = current_fsuid(); 121 inode->i_uid = current_fsuid();
121 inode->i_gid = current_fsgid(); 122 inode->i_gid = current_fsgid();
@@ -210,13 +211,13 @@ out:
210 return error; 211 return error;
211} 212}
212 213
213static int mqueue_get_sb(struct file_system_type *fs_type, 214static struct dentry *mqueue_mount(struct file_system_type *fs_type,
214 int flags, const char *dev_name, 215 int flags, const char *dev_name,
215 void *data, struct vfsmount *mnt) 216 void *data)
216{ 217{
217 if (!(flags & MS_KERNMOUNT)) 218 if (!(flags & MS_KERNMOUNT))
218 data = current->nsproxy->ipc_ns; 219 data = current->nsproxy->ipc_ns;
219 return get_sb_ns(fs_type, flags, data, mqueue_fill_super, mnt); 220 return mount_ns(fs_type, flags, data, mqueue_fill_super);
220} 221}
221 222
222static void init_once(void *foo) 223static void init_once(void *foo)
@@ -236,11 +237,18 @@ static struct inode *mqueue_alloc_inode(struct super_block *sb)
236 return &ei->vfs_inode; 237 return &ei->vfs_inode;
237} 238}
238 239
239static void mqueue_destroy_inode(struct inode *inode) 240static void mqueue_i_callback(struct rcu_head *head)
240{ 241{
242 struct inode *inode = container_of(head, struct inode, i_rcu);
243 INIT_LIST_HEAD(&inode->i_dentry);
241 kmem_cache_free(mqueue_inode_cachep, MQUEUE_I(inode)); 244 kmem_cache_free(mqueue_inode_cachep, MQUEUE_I(inode));
242} 245}
243 246
247static void mqueue_destroy_inode(struct inode *inode)
248{
249 call_rcu(&inode->i_rcu, mqueue_i_callback);
250}
251
244static void mqueue_evict_inode(struct inode *inode) 252static void mqueue_evict_inode(struct inode *inode)
245{ 253{
246 struct mqueue_inode_info *info; 254 struct mqueue_inode_info *info;
@@ -769,7 +777,7 @@ SYSCALL_DEFINE1(mq_unlink, const char __user *, u_name)
769 777
770 inode = dentry->d_inode; 778 inode = dentry->d_inode;
771 if (inode) 779 if (inode)
772 atomic_inc(&inode->i_count); 780 ihold(inode);
773 err = mnt_want_write(ipc_ns->mq_mnt); 781 err = mnt_want_write(ipc_ns->mq_mnt);
774 if (err) 782 if (err)
775 goto out_err; 783 goto out_err;
@@ -1219,6 +1227,7 @@ static const struct file_operations mqueue_file_operations = {
1219 .flush = mqueue_flush_file, 1227 .flush = mqueue_flush_file,
1220 .poll = mqueue_poll_file, 1228 .poll = mqueue_poll_file,
1221 .read = mqueue_read_file, 1229 .read = mqueue_read_file,
1230 .llseek = default_llseek,
1222}; 1231};
1223 1232
1224static const struct super_operations mqueue_super_ops = { 1233static const struct super_operations mqueue_super_ops = {
@@ -1230,7 +1239,7 @@ static const struct super_operations mqueue_super_ops = {
1230 1239
1231static struct file_system_type mqueue_fs_type = { 1240static struct file_system_type mqueue_fs_type = {
1232 .name = "mqueue", 1241 .name = "mqueue",
1233 .get_sb = mqueue_get_sb, 1242 .mount = mqueue_mount,
1234 .kill_sb = kill_litter_super, 1243 .kill_sb = kill_litter_super,
1235}; 1244};
1236 1245
diff --git a/ipc/msg.c b/ipc/msg.c
index 747b65507a91..7385de25788a 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -421,7 +421,7 @@ static int msgctl_down(struct ipc_namespace *ns, int msqid, int cmd,
421 return -EFAULT; 421 return -EFAULT;
422 } 422 }
423 423
424 ipcp = ipcctl_pre_down(&msg_ids(ns), msqid, cmd, 424 ipcp = ipcctl_pre_down(ns, &msg_ids(ns), msqid, cmd,
425 &msqid64.msg_perm, msqid64.msg_qbytes); 425 &msqid64.msg_perm, msqid64.msg_qbytes);
426 if (IS_ERR(ipcp)) 426 if (IS_ERR(ipcp))
427 return PTR_ERR(ipcp); 427 return PTR_ERR(ipcp);
@@ -539,7 +539,7 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
539 success_return = 0; 539 success_return = 0;
540 } 540 }
541 err = -EACCES; 541 err = -EACCES;
542 if (ipcperms(&msq->q_perm, S_IRUGO)) 542 if (ipcperms(ns, &msq->q_perm, S_IRUGO))
543 goto out_unlock; 543 goto out_unlock;
544 544
545 err = security_msg_queue_msgctl(msq, cmd); 545 err = security_msg_queue_msgctl(msq, cmd);
@@ -664,7 +664,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
664 struct msg_sender s; 664 struct msg_sender s;
665 665
666 err = -EACCES; 666 err = -EACCES;
667 if (ipcperms(&msq->q_perm, S_IWUGO)) 667 if (ipcperms(ns, &msq->q_perm, S_IWUGO))
668 goto out_unlock_free; 668 goto out_unlock_free;
669 669
670 err = security_msg_queue_msgsnd(msq, msg, msgflg); 670 err = security_msg_queue_msgsnd(msq, msg, msgflg);
@@ -704,7 +704,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
704 msq->q_stime = get_seconds(); 704 msq->q_stime = get_seconds();
705 705
706 if (!pipelined_send(msq, msg)) { 706 if (!pipelined_send(msq, msg)) {
707 /* noone is waiting for this message, enqueue it */ 707 /* no one is waiting for this message, enqueue it */
708 list_add_tail(&msg->m_list, &msq->q_messages); 708 list_add_tail(&msg->m_list, &msq->q_messages);
709 msq->q_cbytes += msgsz; 709 msq->q_cbytes += msgsz;
710 msq->q_qnum++; 710 msq->q_qnum++;
@@ -774,7 +774,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
774 struct list_head *tmp; 774 struct list_head *tmp;
775 775
776 msg = ERR_PTR(-EACCES); 776 msg = ERR_PTR(-EACCES);
777 if (ipcperms(&msq->q_perm, S_IRUGO)) 777 if (ipcperms(ns, &msq->q_perm, S_IRUGO))
778 goto out_unlock; 778 goto out_unlock;
779 779
780 msg = ERR_PTR(-EAGAIN); 780 msg = ERR_PTR(-EAGAIN);
@@ -842,7 +842,7 @@ long do_msgrcv(int msqid, long *pmtype, void __user *mtext,
842 * Disable preemption. We don't hold a reference to the queue 842 * Disable preemption. We don't hold a reference to the queue
843 * and getting a reference would defeat the idea of a lockless 843 * and getting a reference would defeat the idea of a lockless
844 * operation, thus the code relies on rcu to guarantee the 844 * operation, thus the code relies on rcu to guarantee the
845 * existance of msq: 845 * existence of msq:
846 * Prior to destruction, expunge_all(-EIRDM) changes r_msg. 846 * Prior to destruction, expunge_all(-EIRDM) changes r_msg.
847 * Thus if r_msg is -EAGAIN, then the queue not yet destroyed. 847 * Thus if r_msg is -EAGAIN, then the queue not yet destroyed.
848 * rcu_read_lock() prevents preemption between reading r_msg 848 * rcu_read_lock() prevents preemption between reading r_msg
diff --git a/ipc/msgutil.c b/ipc/msgutil.c
index f095ee268833..8b5ce5d3f3ef 100644
--- a/ipc/msgutil.c
+++ b/ipc/msgutil.c
@@ -32,6 +32,7 @@ struct ipc_namespace init_ipc_ns = {
32 .mq_msg_max = DFLT_MSGMAX, 32 .mq_msg_max = DFLT_MSGMAX,
33 .mq_msgsize_max = DFLT_MSGSIZEMAX, 33 .mq_msgsize_max = DFLT_MSGSIZEMAX,
34#endif 34#endif
35 .user_ns = &init_user_ns,
35}; 36};
36 37
37atomic_t nr_ipc_ns = ATOMIC_INIT(1); 38atomic_t nr_ipc_ns = ATOMIC_INIT(1);
diff --git a/ipc/namespace.c b/ipc/namespace.c
index a1094ff0befa..ce0a647869b1 100644
--- a/ipc/namespace.c
+++ b/ipc/namespace.c
@@ -11,10 +11,13 @@
11#include <linux/slab.h> 11#include <linux/slab.h>
12#include <linux/fs.h> 12#include <linux/fs.h>
13#include <linux/mount.h> 13#include <linux/mount.h>
14#include <linux/user_namespace.h>
15#include <linux/proc_fs.h>
14 16
15#include "util.h" 17#include "util.h"
16 18
17static struct ipc_namespace *create_ipc_ns(void) 19static struct ipc_namespace *create_ipc_ns(struct task_struct *tsk,
20 struct ipc_namespace *old_ns)
18{ 21{
19 struct ipc_namespace *ns; 22 struct ipc_namespace *ns;
20 int err; 23 int err;
@@ -43,14 +46,19 @@ static struct ipc_namespace *create_ipc_ns(void)
43 ipcns_notify(IPCNS_CREATED); 46 ipcns_notify(IPCNS_CREATED);
44 register_ipcns_notifier(ns); 47 register_ipcns_notifier(ns);
45 48
49 ns->user_ns = get_user_ns(task_cred_xxx(tsk, user)->user_ns);
50
46 return ns; 51 return ns;
47} 52}
48 53
49struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns) 54struct ipc_namespace *copy_ipcs(unsigned long flags,
55 struct task_struct *tsk)
50{ 56{
57 struct ipc_namespace *ns = tsk->nsproxy->ipc_ns;
58
51 if (!(flags & CLONE_NEWIPC)) 59 if (!(flags & CLONE_NEWIPC))
52 return get_ipc_ns(ns); 60 return get_ipc_ns(ns);
53 return create_ipc_ns(); 61 return create_ipc_ns(tsk, ns);
54} 62}
55 63
56/* 64/*
@@ -97,7 +105,6 @@ static void free_ipc_ns(struct ipc_namespace *ns)
97 sem_exit_ns(ns); 105 sem_exit_ns(ns);
98 msg_exit_ns(ns); 106 msg_exit_ns(ns);
99 shm_exit_ns(ns); 107 shm_exit_ns(ns);
100 kfree(ns);
101 atomic_dec(&nr_ipc_ns); 108 atomic_dec(&nr_ipc_ns);
102 109
103 /* 110 /*
@@ -105,6 +112,8 @@ static void free_ipc_ns(struct ipc_namespace *ns)
105 * order to have a correct value when recomputing msgmni. 112 * order to have a correct value when recomputing msgmni.
106 */ 113 */
107 ipcns_notify(IPCNS_REMOVED); 114 ipcns_notify(IPCNS_REMOVED);
115 put_user_ns(ns->user_ns);
116 kfree(ns);
108} 117}
109 118
110/* 119/*
@@ -132,3 +141,39 @@ void put_ipc_ns(struct ipc_namespace *ns)
132 free_ipc_ns(ns); 141 free_ipc_ns(ns);
133 } 142 }
134} 143}
144
145static void *ipcns_get(struct task_struct *task)
146{
147 struct ipc_namespace *ns = NULL;
148 struct nsproxy *nsproxy;
149
150 rcu_read_lock();
151 nsproxy = task_nsproxy(task);
152 if (nsproxy)
153 ns = get_ipc_ns(nsproxy->ipc_ns);
154 rcu_read_unlock();
155
156 return ns;
157}
158
159static void ipcns_put(void *ns)
160{
161 return put_ipc_ns(ns);
162}
163
164static int ipcns_install(struct nsproxy *nsproxy, void *ns)
165{
166 /* Ditch state from the old ipc namespace */
167 exit_sem(current);
168 put_ipc_ns(nsproxy->ipc_ns);
169 nsproxy->ipc_ns = get_ipc_ns(ns);
170 return 0;
171}
172
173const struct proc_ns_operations ipcns_operations = {
174 .name = "ipc",
175 .type = CLONE_NEWIPC,
176 .get = ipcns_get,
177 .put = ipcns_put,
178 .install = ipcns_install,
179};
diff --git a/ipc/sem.c b/ipc/sem.c
index 0e0d49bbb867..34193ed69fbe 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -817,7 +817,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
817 } 817 }
818 818
819 err = -EACCES; 819 err = -EACCES;
820 if (ipcperms (&sma->sem_perm, S_IRUGO)) 820 if (ipcperms(ns, &sma->sem_perm, S_IRUGO))
821 goto out_unlock; 821 goto out_unlock;
822 822
823 err = security_sem_semctl(sma, cmd); 823 err = security_sem_semctl(sma, cmd);
@@ -862,7 +862,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
862 nsems = sma->sem_nsems; 862 nsems = sma->sem_nsems;
863 863
864 err = -EACCES; 864 err = -EACCES;
865 if (ipcperms (&sma->sem_perm, (cmd==SETVAL||cmd==SETALL)?S_IWUGO:S_IRUGO)) 865 if (ipcperms(ns, &sma->sem_perm,
866 (cmd == SETVAL || cmd == SETALL) ? S_IWUGO : S_IRUGO))
866 goto out_unlock; 867 goto out_unlock;
867 868
868 err = security_sem_semctl(sma, cmd); 869 err = security_sem_semctl(sma, cmd);
@@ -1047,7 +1048,8 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
1047 return -EFAULT; 1048 return -EFAULT;
1048 } 1049 }
1049 1050
1050 ipcp = ipcctl_pre_down(&sem_ids(ns), semid, cmd, &semid64.sem_perm, 0); 1051 ipcp = ipcctl_pre_down(ns, &sem_ids(ns), semid, cmd,
1052 &semid64.sem_perm, 0);
1051 if (IS_ERR(ipcp)) 1053 if (IS_ERR(ipcp))
1052 return PTR_ERR(ipcp); 1054 return PTR_ERR(ipcp);
1053 1055
@@ -1360,7 +1362,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
1360 * semid identifiers are not unique - find_alloc_undo may have 1362 * semid identifiers are not unique - find_alloc_undo may have
1361 * allocated an undo structure, it was invalidated by an RMID 1363 * allocated an undo structure, it was invalidated by an RMID
1362 * and now a new array with received the same id. Check and fail. 1364 * and now a new array with received the same id. Check and fail.
1363 * This case can be detected checking un->semid. The existance of 1365 * This case can be detected checking un->semid. The existence of
1364 * "un" itself is guaranteed by rcu. 1366 * "un" itself is guaranteed by rcu.
1365 */ 1367 */
1366 error = -EIDRM; 1368 error = -EIDRM;
@@ -1386,7 +1388,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
1386 goto out_unlock_free; 1388 goto out_unlock_free;
1387 1389
1388 error = -EACCES; 1390 error = -EACCES;
1389 if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) 1391 if (ipcperms(ns, &sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
1390 goto out_unlock_free; 1392 goto out_unlock_free;
1391 1393
1392 error = security_sem_semop(sma, sops, nsops, alter); 1394 error = security_sem_semop(sma, sops, nsops, alter);
diff --git a/ipc/shm.c b/ipc/shm.c
index 52ed77eb9713..ab3385a21b27 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -108,7 +108,11 @@ void __init shm_init (void)
108{ 108{
109 shm_init_ns(&init_ipc_ns); 109 shm_init_ns(&init_ipc_ns);
110 ipc_init_proc_interface("sysvipc/shm", 110 ipc_init_proc_interface("sysvipc/shm",
111 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n", 111#if BITS_PER_LONG <= 32
112 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
113#else
114 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
115#endif
112 IPC_SHM_IDS, sysvipc_shm_proc_show); 116 IPC_SHM_IDS, sysvipc_shm_proc_show);
113} 117}
114 118
@@ -298,6 +302,7 @@ static const struct file_operations shm_file_operations = {
298#ifndef CONFIG_MMU 302#ifndef CONFIG_MMU
299 .get_unmapped_area = shm_get_unmapped_area, 303 .get_unmapped_area = shm_get_unmapped_area,
300#endif 304#endif
305 .llseek = noop_llseek,
301}; 306};
302 307
303static const struct file_operations shm_file_operations_huge = { 308static const struct file_operations shm_file_operations_huge = {
@@ -305,6 +310,7 @@ static const struct file_operations shm_file_operations_huge = {
305 .fsync = shm_fsync, 310 .fsync = shm_fsync,
306 .release = shm_release, 311 .release = shm_release,
307 .get_unmapped_area = shm_get_unmapped_area, 312 .get_unmapped_area = shm_get_unmapped_area,
313 .llseek = noop_llseek,
308}; 314};
309 315
310int is_file_shm_hugepages(struct file *file) 316int is_file_shm_hugepages(struct file *file)
@@ -341,7 +347,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
341 struct file * file; 347 struct file * file;
342 char name[13]; 348 char name[13];
343 int id; 349 int id;
344 int acctflag = 0; 350 vm_flags_t acctflag = 0;
345 351
346 if (size < SHMMIN || size > ns->shm_ctlmax) 352 if (size < SHMMIN || size > ns->shm_ctlmax)
347 return -EINVAL; 353 return -EINVAL;
@@ -473,6 +479,7 @@ static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_
473 { 479 {
474 struct shmid_ds out; 480 struct shmid_ds out;
475 481
482 memset(&out, 0, sizeof(out));
476 ipc64_perm_to_ipc_perm(&in->shm_perm, &out.shm_perm); 483 ipc64_perm_to_ipc_perm(&in->shm_perm, &out.shm_perm);
477 out.shm_segsz = in->shm_segsz; 484 out.shm_segsz = in->shm_segsz;
478 out.shm_atime = in->shm_atime; 485 out.shm_atime = in->shm_atime;
@@ -542,6 +549,34 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf
542} 549}
543 550
544/* 551/*
552 * Calculate and add used RSS and swap pages of a shm.
553 * Called with shm_ids.rw_mutex held as a reader
554 */
555static void shm_add_rss_swap(struct shmid_kernel *shp,
556 unsigned long *rss_add, unsigned long *swp_add)
557{
558 struct inode *inode;
559
560 inode = shp->shm_file->f_path.dentry->d_inode;
561
562 if (is_file_hugepages(shp->shm_file)) {
563 struct address_space *mapping = inode->i_mapping;
564 struct hstate *h = hstate_file(shp->shm_file);
565 *rss_add += pages_per_huge_page(h) * mapping->nrpages;
566 } else {
567#ifdef CONFIG_SHMEM
568 struct shmem_inode_info *info = SHMEM_I(inode);
569 spin_lock(&info->lock);
570 *rss_add += inode->i_mapping->nrpages;
571 *swp_add += info->swapped;
572 spin_unlock(&info->lock);
573#else
574 *rss_add += inode->i_mapping->nrpages;
575#endif
576 }
577}
578
579/*
545 * Called with shm_ids.rw_mutex held as a reader 580 * Called with shm_ids.rw_mutex held as a reader
546 */ 581 */
547static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, 582static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
@@ -558,30 +593,13 @@ static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
558 for (total = 0, next_id = 0; total < in_use; next_id++) { 593 for (total = 0, next_id = 0; total < in_use; next_id++) {
559 struct kern_ipc_perm *ipc; 594 struct kern_ipc_perm *ipc;
560 struct shmid_kernel *shp; 595 struct shmid_kernel *shp;
561 struct inode *inode;
562 596
563 ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id); 597 ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
564 if (ipc == NULL) 598 if (ipc == NULL)
565 continue; 599 continue;
566 shp = container_of(ipc, struct shmid_kernel, shm_perm); 600 shp = container_of(ipc, struct shmid_kernel, shm_perm);
567 601
568 inode = shp->shm_file->f_path.dentry->d_inode; 602 shm_add_rss_swap(shp, rss, swp);
569
570 if (is_file_hugepages(shp->shm_file)) {
571 struct address_space *mapping = inode->i_mapping;
572 struct hstate *h = hstate_file(shp->shm_file);
573 *rss += pages_per_huge_page(h) * mapping->nrpages;
574 } else {
575#ifdef CONFIG_SHMEM
576 struct shmem_inode_info *info = SHMEM_I(inode);
577 spin_lock(&info->lock);
578 *rss += inode->i_mapping->nrpages;
579 *swp += info->swapped;
580 spin_unlock(&info->lock);
581#else
582 *rss += inode->i_mapping->nrpages;
583#endif
584 }
585 603
586 total++; 604 total++;
587 } 605 }
@@ -605,7 +623,8 @@ static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
605 return -EFAULT; 623 return -EFAULT;
606 } 624 }
607 625
608 ipcp = ipcctl_pre_down(&shm_ids(ns), shmid, cmd, &shmid64.shm_perm, 0); 626 ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd,
627 &shmid64.shm_perm, 0);
609 if (IS_ERR(ipcp)) 628 if (IS_ERR(ipcp))
610 return PTR_ERR(ipcp); 629 return PTR_ERR(ipcp);
611 630
@@ -719,7 +738,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
719 result = 0; 738 result = 0;
720 } 739 }
721 err = -EACCES; 740 err = -EACCES;
722 if (ipcperms (&shp->shm_perm, S_IRUGO)) 741 if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
723 goto out_unlock; 742 goto out_unlock;
724 err = security_shm_shmctl(shp, cmd); 743 err = security_shm_shmctl(shp, cmd);
725 if (err) 744 if (err)
@@ -755,7 +774,7 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
755 774
756 audit_ipc_obj(&(shp->shm_perm)); 775 audit_ipc_obj(&(shp->shm_perm));
757 776
758 if (!capable(CAP_IPC_LOCK)) { 777 if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
759 uid_t euid = current_euid(); 778 uid_t euid = current_euid();
760 err = -EPERM; 779 err = -EPERM;
761 if (euid != shp->shm_perm.uid && 780 if (euid != shp->shm_perm.uid &&
@@ -870,7 +889,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
870 } 889 }
871 890
872 err = -EACCES; 891 err = -EACCES;
873 if (ipcperms(&shp->shm_perm, acc_mode)) 892 if (ipcperms(ns, &shp->shm_perm, acc_mode))
874 goto out_unlock; 893 goto out_unlock;
875 894
876 err = security_shm_shmat(shp, shmaddr, shmflg); 895 err = security_shm_shmat(shp, shmaddr, shmflg);
@@ -1037,7 +1056,7 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
1037 /* 1056 /*
1038 * We need look no further than the maximum address a fragment 1057 * We need look no further than the maximum address a fragment
1039 * could possibly have landed at. Also cast things to loff_t to 1058 * could possibly have landed at. Also cast things to loff_t to
1040 * prevent overflows and make comparisions vs. equal-width types. 1059 * prevent overflows and make comparisons vs. equal-width types.
1041 */ 1060 */
1042 size = PAGE_ALIGN(size); 1061 size = PAGE_ALIGN(size);
1043 while (vma && (loff_t)(vma->vm_end - addr) <= size) { 1062 while (vma && (loff_t)(vma->vm_end - addr) <= size) {
@@ -1070,6 +1089,9 @@ SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
1070static int sysvipc_shm_proc_show(struct seq_file *s, void *it) 1089static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1071{ 1090{
1072 struct shmid_kernel *shp = it; 1091 struct shmid_kernel *shp = it;
1092 unsigned long rss = 0, swp = 0;
1093
1094 shm_add_rss_swap(shp, &rss, &swp);
1073 1095
1074#if BITS_PER_LONG <= 32 1096#if BITS_PER_LONG <= 32
1075#define SIZE_SPEC "%10lu" 1097#define SIZE_SPEC "%10lu"
@@ -1079,7 +1101,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1079 1101
1080 return seq_printf(s, 1102 return seq_printf(s,
1081 "%10d %10d %4o " SIZE_SPEC " %5u %5u " 1103 "%10d %10d %4o " SIZE_SPEC " %5u %5u "
1082 "%5lu %5u %5u %5u %5u %10lu %10lu %10lu\n", 1104 "%5lu %5u %5u %5u %5u %10lu %10lu %10lu "
1105 SIZE_SPEC " " SIZE_SPEC "\n",
1083 shp->shm_perm.key, 1106 shp->shm_perm.key,
1084 shp->shm_perm.id, 1107 shp->shm_perm.id,
1085 shp->shm_perm.mode, 1108 shp->shm_perm.mode,
@@ -1093,6 +1116,8 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1093 shp->shm_perm.cgid, 1116 shp->shm_perm.cgid,
1094 shp->shm_atim, 1117 shp->shm_atim,
1095 shp->shm_dtim, 1118 shp->shm_dtim,
1096 shp->shm_ctim); 1119 shp->shm_ctim,
1120 rss * PAGE_SIZE,
1121 swp * PAGE_SIZE);
1097} 1122}
1098#endif 1123#endif
diff --git a/ipc/util.c b/ipc/util.c
index 69a0cc13d966..5c0d28921ba8 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -317,6 +317,7 @@ retry:
317 317
318/** 318/**
319 * ipc_check_perms - check security and permissions for an IPC 319 * ipc_check_perms - check security and permissions for an IPC
320 * @ns: IPC namespace
320 * @ipcp: ipc permission set 321 * @ipcp: ipc permission set
321 * @ops: the actual security routine to call 322 * @ops: the actual security routine to call
322 * @params: its parameters 323 * @params: its parameters
@@ -329,12 +330,14 @@ retry:
329 * 330 *
330 * It is called with ipc_ids.rw_mutex and ipcp->lock held. 331 * It is called with ipc_ids.rw_mutex and ipcp->lock held.
331 */ 332 */
332static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops, 333static int ipc_check_perms(struct ipc_namespace *ns,
333 struct ipc_params *params) 334 struct kern_ipc_perm *ipcp,
335 struct ipc_ops *ops,
336 struct ipc_params *params)
334{ 337{
335 int err; 338 int err;
336 339
337 if (ipcperms(ipcp, params->flg)) 340 if (ipcperms(ns, ipcp, params->flg))
338 err = -EACCES; 341 err = -EACCES;
339 else { 342 else {
340 err = ops->associate(ipcp, params->flg); 343 err = ops->associate(ipcp, params->flg);
@@ -396,7 +399,7 @@ retry:
396 * ipc_check_perms returns the IPC id on 399 * ipc_check_perms returns the IPC id on
397 * success 400 * success
398 */ 401 */
399 err = ipc_check_perms(ipcp, ops, params); 402 err = ipc_check_perms(ns, ipcp, ops, params);
400 } 403 }
401 ipc_unlock(ipcp); 404 ipc_unlock(ipcp);
402 } 405 }
@@ -605,15 +608,18 @@ void ipc_rcu_putref(void *ptr)
605 608
606/** 609/**
607 * ipcperms - check IPC permissions 610 * ipcperms - check IPC permissions
611 * @ns: IPC namespace
608 * @ipcp: IPC permission set 612 * @ipcp: IPC permission set
609 * @flag: desired permission set. 613 * @flag: desired permission set.
610 * 614 *
611 * Check user, group, other permissions for access 615 * Check user, group, other permissions for access
612 * to ipc resources. return 0 if allowed 616 * to ipc resources. return 0 if allowed
617 *
618 * @flag will most probably be 0 or S_...UGO from <linux/stat.h>
613 */ 619 */
614 620
615int ipcperms (struct kern_ipc_perm *ipcp, short flag) 621int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
616{ /* flag will most probably be 0 or S_...UGO from <linux/stat.h> */ 622{
617 uid_t euid = current_euid(); 623 uid_t euid = current_euid();
618 int requested_mode, granted_mode; 624 int requested_mode, granted_mode;
619 625
@@ -627,7 +633,7 @@ int ipcperms (struct kern_ipc_perm *ipcp, short flag)
627 granted_mode >>= 3; 633 granted_mode >>= 3;
628 /* is there some bit set in requested_mode but not in granted_mode? */ 634 /* is there some bit set in requested_mode but not in granted_mode? */
629 if ((requested_mode & ~granted_mode & 0007) && 635 if ((requested_mode & ~granted_mode & 0007) &&
630 !capable(CAP_IPC_OWNER)) 636 !ns_capable(ns->user_ns, CAP_IPC_OWNER))
631 return -1; 637 return -1;
632 638
633 return security_ipc_permission(ipcp, flag); 639 return security_ipc_permission(ipcp, flag);
@@ -765,6 +771,7 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
765 771
766/** 772/**
767 * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd 773 * ipcctl_pre_down - retrieve an ipc and check permissions for some IPC_XXX cmd
774 * @ns: the ipc namespace
768 * @ids: the table of ids where to look for the ipc 775 * @ids: the table of ids where to look for the ipc
769 * @id: the id of the ipc to retrieve 776 * @id: the id of the ipc to retrieve
770 * @cmd: the cmd to check 777 * @cmd: the cmd to check
@@ -779,7 +786,8 @@ void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
779 * - returns the ipc with both ipc and rw_mutex locks held in case of success 786 * - returns the ipc with both ipc and rw_mutex locks held in case of success
780 * or an err-code without any lock held otherwise. 787 * or an err-code without any lock held otherwise.
781 */ 788 */
782struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, 789struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
790 struct ipc_ids *ids, int id, int cmd,
783 struct ipc64_perm *perm, int extra_perm) 791 struct ipc64_perm *perm, int extra_perm)
784{ 792{
785 struct kern_ipc_perm *ipcp; 793 struct kern_ipc_perm *ipcp;
@@ -799,8 +807,8 @@ struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd,
799 perm->gid, perm->mode); 807 perm->gid, perm->mode);
800 808
801 euid = current_euid(); 809 euid = current_euid();
802 if (euid == ipcp->cuid || 810 if (euid == ipcp->cuid || euid == ipcp->uid ||
803 euid == ipcp->uid || capable(CAP_SYS_ADMIN)) 811 ns_capable(ns->user_ns, CAP_SYS_ADMIN))
804 return ipcp; 812 return ipcp;
805 813
806 err = -EPERM; 814 err = -EPERM;
diff --git a/ipc/util.h b/ipc/util.h
index 764b51a37a6a..6f5c20bedaab 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -103,7 +103,7 @@ int ipc_get_maxid(struct ipc_ids *);
103void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *); 103void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *);
104 104
105/* must be called with ipcp locked */ 105/* must be called with ipcp locked */
106int ipcperms(struct kern_ipc_perm *ipcp, short flg); 106int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
107 107
108/* for rare, potentially huge allocations. 108/* for rare, potentially huge allocations.
109 * both function can sleep 109 * both function can sleep
@@ -126,7 +126,8 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *, int);
126void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); 126void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
127void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); 127void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
128void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out); 128void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out);
129struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, 129struct kern_ipc_perm *ipcctl_pre_down(struct ipc_namespace *ns,
130 struct ipc_ids *ids, int id, int cmd,
130 struct ipc64_perm *perm, int extra_perm); 131 struct ipc64_perm *perm, int extra_perm);
131 132
132#ifndef __ARCH_WANT_IPC_PARSE_VERSION 133#ifndef __ARCH_WANT_IPC_PARSE_VERSION