diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /ipc | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (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.c | 6 | ||||
-rw-r--r-- | ipc/compat_mq.c | 5 | ||||
-rw-r--r-- | ipc/mqueue.c | 21 | ||||
-rw-r--r-- | ipc/msg.c | 12 | ||||
-rw-r--r-- | ipc/msgutil.c | 1 | ||||
-rw-r--r-- | ipc/namespace.c | 53 | ||||
-rw-r--r-- | ipc/sem.c | 12 | ||||
-rw-r--r-- | ipc/shm.c | 79 | ||||
-rw-r--r-- | ipc/util.c | 28 | ||||
-rw-r--r-- | ipc/util.h | 5 |
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 | ||
213 | static int mqueue_get_sb(struct file_system_type *fs_type, | 214 | static 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 | ||
222 | static void init_once(void *foo) | 223 | static 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 | ||
239 | static void mqueue_destroy_inode(struct inode *inode) | 240 | static 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 | ||
247 | static void mqueue_destroy_inode(struct inode *inode) | ||
248 | { | ||
249 | call_rcu(&inode->i_rcu, mqueue_i_callback); | ||
250 | } | ||
251 | |||
244 | static void mqueue_evict_inode(struct inode *inode) | 252 | static 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 | ||
1224 | static const struct super_operations mqueue_super_ops = { | 1233 | static const struct super_operations mqueue_super_ops = { |
@@ -1230,7 +1239,7 @@ static const struct super_operations mqueue_super_ops = { | |||
1230 | 1239 | ||
1231 | static struct file_system_type mqueue_fs_type = { | 1240 | static 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 | ||
@@ -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 | ||
37 | atomic_t nr_ipc_ns = ATOMIC_INIT(1); | 38 | atomic_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 | ||
17 | static struct ipc_namespace *create_ipc_ns(void) | 19 | static 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 | ||
49 | struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns) | 54 | struct 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 | |||
145 | static 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 | |||
159 | static void ipcns_put(void *ns) | ||
160 | { | ||
161 | return put_ipc_ns(ns); | ||
162 | } | ||
163 | |||
164 | static 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 | |||
173 | const 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 | }; | ||
@@ -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); |
@@ -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 | ||
303 | static const struct file_operations shm_file_operations_huge = { | 308 | static 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 | ||
310 | int is_file_shm_hugepages(struct file *file) | 316 | int 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 | */ | ||
555 | static 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 | */ |
547 | static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss, | 582 | static 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) | |||
1070 | static int sysvipc_shm_proc_show(struct seq_file *s, void *it) | 1089 | static 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 | */ |
332 | static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops, | 333 | static 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 | ||
615 | int ipcperms (struct kern_ipc_perm *ipcp, short flag) | 621 | int 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 | */ |
782 | struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, | 789 | struct 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 *); | |||
103 | void ipc_rmid(struct ipc_ids *, struct kern_ipc_perm *); | 103 | void 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 */ |
106 | int ipcperms(struct kern_ipc_perm *ipcp, short flg); | 106 | int 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); | |||
126 | void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); | 126 | void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out); |
127 | void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); | 127 | void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out); |
128 | void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out); | 128 | void ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out); |
129 | struct kern_ipc_perm *ipcctl_pre_down(struct ipc_ids *ids, int id, int cmd, | 129 | struct 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 |