aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'ipc')
-rw-r--r--ipc/mqueue.c3
-rw-r--r--ipc/shm.c260
-rw-r--r--ipc/util.c7
3 files changed, 184 insertions, 86 deletions
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 0b5ecbe5f045..554ac368be79 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -731,7 +731,8 @@ asmlinkage long sys_mq_unlink(const char __user *u_name)
731 if (IS_ERR(name)) 731 if (IS_ERR(name))
732 return PTR_ERR(name); 732 return PTR_ERR(name);
733 733
734 mutex_lock(&mqueue_mnt->mnt_root->d_inode->i_mutex); 734 mutex_lock_nested(&mqueue_mnt->mnt_root->d_inode->i_mutex,
735 I_MUTEX_PARENT);
735 dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name)); 736 dentry = lookup_one_len(name, mqueue_mnt->mnt_root, strlen(name));
736 if (IS_ERR(dentry)) { 737 if (IS_ERR(dentry)) {
737 err = PTR_ERR(dentry); 738 err = PTR_ERR(dentry);
diff --git a/ipc/shm.c b/ipc/shm.c
index 5bb617f6306e..4fefbad7096d 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -37,11 +37,21 @@
37#include <linux/seq_file.h> 37#include <linux/seq_file.h>
38#include <linux/mutex.h> 38#include <linux/mutex.h>
39#include <linux/nsproxy.h> 39#include <linux/nsproxy.h>
40#include <linux/mount.h>
40 41
41#include <asm/uaccess.h> 42#include <asm/uaccess.h>
42 43
43#include "util.h" 44#include "util.h"
44 45
46struct shm_file_data {
47 int id;
48 struct ipc_namespace *ns;
49 struct file *file;
50 const struct vm_operations_struct *vm_ops;
51};
52
53#define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data))
54
45static const struct file_operations shm_file_operations; 55static const struct file_operations shm_file_operations;
46static struct vm_operations_struct shm_vm_ops; 56static struct vm_operations_struct shm_vm_ops;
47 57
@@ -60,8 +70,8 @@ static struct ipc_ids init_shm_ids;
60 70
61static int newseg (struct ipc_namespace *ns, key_t key, 71static int newseg (struct ipc_namespace *ns, key_t key,
62 int shmflg, size_t size); 72 int shmflg, size_t size);
63static void shm_open (struct vm_area_struct *shmd); 73static void shm_open(struct vm_area_struct *vma);
64static void shm_close (struct vm_area_struct *shmd); 74static void shm_close(struct vm_area_struct *vma);
65static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp); 75static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
66#ifdef CONFIG_PROC_FS 76#ifdef CONFIG_PROC_FS
67static int sysvipc_shm_proc_show(struct seq_file *s, void *it); 77static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
@@ -150,11 +160,14 @@ static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp)
150 160
151 161
152 162
153static inline void shm_inc(struct ipc_namespace *ns, int id) 163/* This is called by fork, once for every shm attach. */
164static void shm_open(struct vm_area_struct *vma)
154{ 165{
166 struct file *file = vma->vm_file;
167 struct shm_file_data *sfd = shm_file_data(file);
155 struct shmid_kernel *shp; 168 struct shmid_kernel *shp;
156 169
157 shp = shm_lock(ns, id); 170 shp = shm_lock(sfd->ns, sfd->id);
158 BUG_ON(!shp); 171 BUG_ON(!shp);
159 shp->shm_atim = get_seconds(); 172 shp->shm_atim = get_seconds();
160 shp->shm_lprid = current->tgid; 173 shp->shm_lprid = current->tgid;
@@ -162,15 +175,6 @@ static inline void shm_inc(struct ipc_namespace *ns, int id)
162 shm_unlock(shp); 175 shm_unlock(shp);
163} 176}
164 177
165#define shm_file_ns(file) (*((struct ipc_namespace **)&(file)->private_data))
166
167/* This is called by fork, once for every shm attach. */
168static void shm_open(struct vm_area_struct *shmd)
169{
170 shm_inc(shm_file_ns(shmd->vm_file),
171 shmd->vm_file->f_path.dentry->d_inode->i_ino);
172}
173
174/* 178/*
175 * shm_destroy - free the struct shmid_kernel 179 * shm_destroy - free the struct shmid_kernel
176 * 180 *
@@ -195,23 +199,21 @@ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
195} 199}
196 200
197/* 201/*
198 * remove the attach descriptor shmd. 202 * remove the attach descriptor vma.
199 * free memory for segment if it is marked destroyed. 203 * free memory for segment if it is marked destroyed.
200 * The descriptor has already been removed from the current->mm->mmap list 204 * The descriptor has already been removed from the current->mm->mmap list
201 * and will later be kfree()d. 205 * and will later be kfree()d.
202 */ 206 */
203static void shm_close (struct vm_area_struct *shmd) 207static void shm_close(struct vm_area_struct *vma)
204{ 208{
205 struct file * file = shmd->vm_file; 209 struct file * file = vma->vm_file;
206 int id = file->f_path.dentry->d_inode->i_ino; 210 struct shm_file_data *sfd = shm_file_data(file);
207 struct shmid_kernel *shp; 211 struct shmid_kernel *shp;
208 struct ipc_namespace *ns; 212 struct ipc_namespace *ns = sfd->ns;
209
210 ns = shm_file_ns(file);
211 213
212 mutex_lock(&shm_ids(ns).mutex); 214 mutex_lock(&shm_ids(ns).mutex);
213 /* remove from the list of attaches of the shm segment */ 215 /* remove from the list of attaches of the shm segment */
214 shp = shm_lock(ns, id); 216 shp = shm_lock(ns, sfd->id);
215 BUG_ON(!shp); 217 BUG_ON(!shp);
216 shp->shm_lprid = current->tgid; 218 shp->shm_lprid = current->tgid;
217 shp->shm_dtim = get_seconds(); 219 shp->shm_dtim = get_seconds();
@@ -224,46 +226,111 @@ static void shm_close (struct vm_area_struct *shmd)
224 mutex_unlock(&shm_ids(ns).mutex); 226 mutex_unlock(&shm_ids(ns).mutex);
225} 227}
226 228
229static struct page *shm_nopage(struct vm_area_struct *vma,
230 unsigned long address, int *type)
231{
232 struct file *file = vma->vm_file;
233 struct shm_file_data *sfd = shm_file_data(file);
234
235 return sfd->vm_ops->nopage(vma, address, type);
236}
237
238#ifdef CONFIG_NUMA
239int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
240{
241 struct file *file = vma->vm_file;
242 struct shm_file_data *sfd = shm_file_data(file);
243 int err = 0;
244 if (sfd->vm_ops->set_policy)
245 err = sfd->vm_ops->set_policy(vma, new);
246 return err;
247}
248
249struct mempolicy *shm_get_policy(struct vm_area_struct *vma, unsigned long addr)
250{
251 struct file *file = vma->vm_file;
252 struct shm_file_data *sfd = shm_file_data(file);
253 struct mempolicy *pol = NULL;
254
255 if (sfd->vm_ops->get_policy)
256 pol = sfd->vm_ops->get_policy(vma, addr);
257 else
258 pol = vma->vm_policy;
259 return pol;
260}
261#endif
262
227static int shm_mmap(struct file * file, struct vm_area_struct * vma) 263static int shm_mmap(struct file * file, struct vm_area_struct * vma)
228{ 264{
265 struct shm_file_data *sfd = shm_file_data(file);
229 int ret; 266 int ret;
230 267
231 ret = shmem_mmap(file, vma); 268 ret = sfd->file->f_op->mmap(sfd->file, vma);
232 if (ret == 0) { 269 if (ret != 0)
233 vma->vm_ops = &shm_vm_ops; 270 return ret;
234 if (!(vma->vm_flags & VM_WRITE)) 271 sfd->vm_ops = vma->vm_ops;
235 vma->vm_flags &= ~VM_MAYWRITE; 272 vma->vm_ops = &shm_vm_ops;
236 shm_inc(shm_file_ns(file), file->f_path.dentry->d_inode->i_ino); 273 shm_open(vma);
237 }
238 274
239 return ret; 275 return ret;
240} 276}
241 277
242static int shm_release(struct inode *ino, struct file *file) 278static int shm_release(struct inode *ino, struct file *file)
243{ 279{
244 struct ipc_namespace *ns; 280 struct shm_file_data *sfd = shm_file_data(file);
245 281
246 ns = shm_file_ns(file); 282 put_ipc_ns(sfd->ns);
247 put_ipc_ns(ns); 283 shm_file_data(file) = NULL;
248 shm_file_ns(file) = NULL; 284 kfree(sfd);
249 return 0; 285 return 0;
250} 286}
251 287
288static int shm_fsync(struct file *file, struct dentry *dentry, int datasync)
289{
290 int (*fsync) (struct file *, struct dentry *, int datasync);
291 struct shm_file_data *sfd = shm_file_data(file);
292 int ret = -EINVAL;
293
294 fsync = sfd->file->f_op->fsync;
295 if (fsync)
296 ret = fsync(sfd->file, sfd->file->f_path.dentry, datasync);
297 return ret;
298}
299
300static unsigned long shm_get_unmapped_area(struct file *file,
301 unsigned long addr, unsigned long len, unsigned long pgoff,
302 unsigned long flags)
303{
304 struct shm_file_data *sfd = shm_file_data(file);
305 return get_unmapped_area(sfd->file, addr, len, pgoff, flags);
306}
307
308int is_file_shm_hugepages(struct file *file)
309{
310 int ret = 0;
311
312 if (file->f_op == &shm_file_operations) {
313 struct shm_file_data *sfd;
314 sfd = shm_file_data(file);
315 ret = is_file_hugepages(sfd->file);
316 }
317 return ret;
318}
319
252static const struct file_operations shm_file_operations = { 320static const struct file_operations shm_file_operations = {
253 .mmap = shm_mmap, 321 .mmap = shm_mmap,
322 .fsync = shm_fsync,
254 .release = shm_release, 323 .release = shm_release,
255#ifndef CONFIG_MMU 324 .get_unmapped_area = shm_get_unmapped_area,
256 .get_unmapped_area = shmem_get_unmapped_area,
257#endif
258}; 325};
259 326
260static struct vm_operations_struct shm_vm_ops = { 327static struct vm_operations_struct shm_vm_ops = {
261 .open = shm_open, /* callback for a new vm-area open */ 328 .open = shm_open, /* callback for a new vm-area open */
262 .close = shm_close, /* callback for when the vm-area is released */ 329 .close = shm_close, /* callback for when the vm-area is released */
263 .nopage = shmem_nopage, 330 .nopage = shm_nopage,
264#if defined(CONFIG_NUMA) && defined(CONFIG_SHMEM) 331#if defined(CONFIG_NUMA)
265 .set_policy = shmem_set_policy, 332 .set_policy = shm_set_policy,
266 .get_policy = shmem_get_policy, 333 .get_policy = shm_get_policy,
267#endif 334#endif
268}; 335};
269 336
@@ -330,13 +397,6 @@ static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size)
330 shp->shm_nattch = 0; 397 shp->shm_nattch = 0;
331 shp->id = shm_buildid(ns, id, shp->shm_perm.seq); 398 shp->id = shm_buildid(ns, id, shp->shm_perm.seq);
332 shp->shm_file = file; 399 shp->shm_file = file;
333 file->f_path.dentry->d_inode->i_ino = shp->id;
334
335 shm_file_ns(file) = get_ipc_ns(ns);
336
337 /* Hugetlb ops would have already been assigned. */
338 if (!(shmflg & SHM_HUGETLB))
339 file->f_op = &shm_file_operations;
340 400
341 ns->shm_tot += numpages; 401 ns->shm_tot += numpages;
342 shm_unlock(shp); 402 shm_unlock(shp);
@@ -607,10 +667,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
607 tbuf.shm_ctime = shp->shm_ctim; 667 tbuf.shm_ctime = shp->shm_ctim;
608 tbuf.shm_cpid = shp->shm_cprid; 668 tbuf.shm_cpid = shp->shm_cprid;
609 tbuf.shm_lpid = shp->shm_lprid; 669 tbuf.shm_lpid = shp->shm_lprid;
610 if (!is_file_hugepages(shp->shm_file)) 670 tbuf.shm_nattch = shp->shm_nattch;
611 tbuf.shm_nattch = shp->shm_nattch;
612 else
613 tbuf.shm_nattch = file_count(shp->shm_file) - 1;
614 shm_unlock(shp); 671 shm_unlock(shp);
615 if(copy_shmid_to_user (buf, &tbuf, version)) 672 if(copy_shmid_to_user (buf, &tbuf, version))
616 err = -EFAULT; 673 err = -EFAULT;
@@ -779,13 +836,16 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
779 unsigned long flags; 836 unsigned long flags;
780 unsigned long prot; 837 unsigned long prot;
781 int acc_mode; 838 int acc_mode;
782 void *user_addr; 839 unsigned long user_addr;
783 struct ipc_namespace *ns; 840 struct ipc_namespace *ns;
841 struct shm_file_data *sfd;
842 struct path path;
843 mode_t f_mode;
784 844
785 if (shmid < 0) { 845 err = -EINVAL;
786 err = -EINVAL; 846 if (shmid < 0)
787 goto out; 847 goto out;
788 } else if ((addr = (ulong)shmaddr)) { 848 else if ((addr = (ulong)shmaddr)) {
789 if (addr & (SHMLBA-1)) { 849 if (addr & (SHMLBA-1)) {
790 if (shmflg & SHM_RND) 850 if (shmflg & SHM_RND)
791 addr &= ~(SHMLBA-1); /* round down */ 851 addr &= ~(SHMLBA-1); /* round down */
@@ -793,12 +853,12 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
793#ifndef __ARCH_FORCE_SHMLBA 853#ifndef __ARCH_FORCE_SHMLBA
794 if (addr & ~PAGE_MASK) 854 if (addr & ~PAGE_MASK)
795#endif 855#endif
796 return -EINVAL; 856 goto out;
797 } 857 }
798 flags = MAP_SHARED | MAP_FIXED; 858 flags = MAP_SHARED | MAP_FIXED;
799 } else { 859 } else {
800 if ((shmflg & SHM_REMAP)) 860 if ((shmflg & SHM_REMAP))
801 return -EINVAL; 861 goto out;
802 862
803 flags = MAP_SHARED; 863 flags = MAP_SHARED;
804 } 864 }
@@ -806,9 +866,11 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
806 if (shmflg & SHM_RDONLY) { 866 if (shmflg & SHM_RDONLY) {
807 prot = PROT_READ; 867 prot = PROT_READ;
808 acc_mode = S_IRUGO; 868 acc_mode = S_IRUGO;
869 f_mode = FMODE_READ;
809 } else { 870 } else {
810 prot = PROT_READ | PROT_WRITE; 871 prot = PROT_READ | PROT_WRITE;
811 acc_mode = S_IRUGO | S_IWUGO; 872 acc_mode = S_IRUGO | S_IWUGO;
873 f_mode = FMODE_READ | FMODE_WRITE;
812 } 874 }
813 if (shmflg & SHM_EXEC) { 875 if (shmflg & SHM_EXEC) {
814 prot |= PROT_EXEC; 876 prot |= PROT_EXEC;
@@ -821,35 +883,50 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
821 */ 883 */
822 ns = current->nsproxy->ipc_ns; 884 ns = current->nsproxy->ipc_ns;
823 shp = shm_lock(ns, shmid); 885 shp = shm_lock(ns, shmid);
824 if(shp == NULL) { 886 if(shp == NULL)
825 err = -EINVAL;
826 goto out; 887 goto out;
827 } 888
828 err = shm_checkid(ns, shp,shmid); 889 err = shm_checkid(ns, shp,shmid);
829 if (err) { 890 if (err)
830 shm_unlock(shp); 891 goto out_unlock;
831 goto out; 892
832 } 893 err = -EACCES;
833 if (ipcperms(&shp->shm_perm, acc_mode)) { 894 if (ipcperms(&shp->shm_perm, acc_mode))
834 shm_unlock(shp); 895 goto out_unlock;
835 err = -EACCES;
836 goto out;
837 }
838 896
839 err = security_shm_shmat(shp, shmaddr, shmflg); 897 err = security_shm_shmat(shp, shmaddr, shmflg);
840 if (err) { 898 if (err)
841 shm_unlock(shp); 899 goto out_unlock;
842 return err; 900
843 } 901 path.dentry = dget(shp->shm_file->f_path.dentry);
844 902 path.mnt = mntget(shp->shm_file->f_path.mnt);
845 file = shp->shm_file;
846 size = i_size_read(file->f_path.dentry->d_inode);
847 shp->shm_nattch++; 903 shp->shm_nattch++;
904 size = i_size_read(path.dentry->d_inode);
848 shm_unlock(shp); 905 shm_unlock(shp);
849 906
907 err = -ENOMEM;
908 sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
909 if (!sfd)
910 goto out_put_path;
911
912 err = -ENOMEM;
913 file = get_empty_filp();
914 if (!file)
915 goto out_free;
916
917 file->f_op = &shm_file_operations;
918 file->private_data = sfd;
919 file->f_path = path;
920 file->f_mapping = shp->shm_file->f_mapping;
921 file->f_mode = f_mode;
922 sfd->id = shp->id;
923 sfd->ns = get_ipc_ns(ns);
924 sfd->file = shp->shm_file;
925 sfd->vm_ops = NULL;
926
850 down_write(&current->mm->mmap_sem); 927 down_write(&current->mm->mmap_sem);
851 if (addr && !(shmflg & SHM_REMAP)) { 928 if (addr && !(shmflg & SHM_REMAP)) {
852 user_addr = ERR_PTR(-EINVAL); 929 err = -EINVAL;
853 if (find_vma_intersection(current->mm, addr, addr + size)) 930 if (find_vma_intersection(current->mm, addr, addr + size))
854 goto invalid; 931 goto invalid;
855 /* 932 /*
@@ -861,11 +938,17 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
861 goto invalid; 938 goto invalid;
862 } 939 }
863 940
864 user_addr = (void*) do_mmap (file, addr, size, prot, flags, 0); 941 user_addr = do_mmap (file, addr, size, prot, flags, 0);
865 942 *raddr = user_addr;
943 err = 0;
944 if (IS_ERR_VALUE(user_addr))
945 err = (long)user_addr;
866invalid: 946invalid:
867 up_write(&current->mm->mmap_sem); 947 up_write(&current->mm->mmap_sem);
868 948
949 fput(file);
950
951out_nattch:
869 mutex_lock(&shm_ids(ns).mutex); 952 mutex_lock(&shm_ids(ns).mutex);
870 shp = shm_lock(ns, shmid); 953 shp = shm_lock(ns, shmid);
871 BUG_ON(!shp); 954 BUG_ON(!shp);
@@ -877,12 +960,19 @@ invalid:
877 shm_unlock(shp); 960 shm_unlock(shp);
878 mutex_unlock(&shm_ids(ns).mutex); 961 mutex_unlock(&shm_ids(ns).mutex);
879 962
880 *raddr = (unsigned long) user_addr;
881 err = 0;
882 if (IS_ERR(user_addr))
883 err = PTR_ERR(user_addr);
884out: 963out:
885 return err; 964 return err;
965
966out_unlock:
967 shm_unlock(shp);
968 goto out;
969
970out_free:
971 kfree(sfd);
972out_put_path:
973 dput(path.dentry);
974 mntput(path.mnt);
975 goto out_nattch;
886} 976}
887 977
888asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg) 978asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg)
@@ -944,7 +1034,7 @@ asmlinkage long sys_shmdt(char __user *shmaddr)
944 * a fragment created by mprotect() and/or munmap(), or it 1034 * a fragment created by mprotect() and/or munmap(), or it
945 * otherwise it starts at this address with no hassles. 1035 * otherwise it starts at this address with no hassles.
946 */ 1036 */
947 if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) && 1037 if ((vma->vm_ops == &shm_vm_ops) &&
948 (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) { 1038 (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
949 1039
950 1040
@@ -973,7 +1063,7 @@ asmlinkage long sys_shmdt(char __user *shmaddr)
973 next = vma->vm_next; 1063 next = vma->vm_next;
974 1064
975 /* finding a matching vma now does not alter retval */ 1065 /* finding a matching vma now does not alter retval */
976 if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) && 1066 if ((vma->vm_ops == &shm_vm_ops) &&
977 (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) 1067 (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
978 1068
979 do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start); 1069 do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
@@ -1004,7 +1094,7 @@ static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1004 shp->shm_segsz, 1094 shp->shm_segsz,
1005 shp->shm_cprid, 1095 shp->shm_cprid,
1006 shp->shm_lprid, 1096 shp->shm_lprid,
1007 is_file_hugepages(shp->shm_file) ? (file_count(shp->shm_file) - 1) : shp->shm_nattch, 1097 shp->shm_nattch,
1008 shp->shm_perm.uid, 1098 shp->shm_perm.uid,
1009 shp->shm_perm.gid, 1099 shp->shm_perm.gid,
1010 shp->shm_perm.cuid, 1100 shp->shm_perm.cuid,
diff --git a/ipc/util.c b/ipc/util.c
index 08a647965b9e..0b652387d169 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -144,6 +144,13 @@ void free_ipc_ns(struct kref *kref)
144 shm_exit_ns(ns); 144 shm_exit_ns(ns);
145 kfree(ns); 145 kfree(ns);
146} 146}
147#else
148int copy_ipcs(unsigned long flags, struct task_struct *tsk)
149{
150 if (flags & CLONE_NEWIPC)
151 return -EINVAL;
152 return 0;
153}
147#endif 154#endif
148 155
149/** 156/**