Blame view

ipc/shm.c 25.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  /*
   * linux/ipc/shm.c
   * Copyright (C) 1992, 1993 Krishna Balasubramanian
   *	 Many improvements/fixes by Bruno Haible.
   * Replaced `struct shm_desc' by `struct vm_area_struct', July 1994.
   * Fixed the shm swap deallocation (shm_unuse()), August 1998 Andrea Arcangeli.
   *
   * /proc/sysvipc/shm support (c) 1999 Dragos Acostachioaie <dragos@iname.com>
   * BIGMEM support, Andrea Arcangeli <andrea@suse.de>
   * SMP thread shm, Jean-Luc Boyard <jean-luc.boyard@siemens.fr>
   * HIGHMEM support, Ingo Molnar <mingo@redhat.com>
   * Make shmmax, shmall, shmmni sysctl'able, Christoph Rohland <cr@sap.com>
   * Shared /dev/zero support, Kanoj Sarcar <kanoj@sgi.com>
   * Move the mm functionality over to mm/shmem.c, Christoph Rohland <cr@sap.com>
   *
073115d6b   Steve Grubb   [PATCH] Rework of...
16
17
   * support for audit of ipc object properties and permission changes
   * Dustin Kirkland <dustin.kirkland@us.ibm.com>
4e9823111   Kirill Korotaev   [PATCH] IPC names...
18
19
20
21
   *
   * namespaces support
   * OpenVZ, SWsoft Inc.
   * Pavel Emelianov <xemul@openvz.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
29
  #include <linux/slab.h>
  #include <linux/mm.h>
  #include <linux/hugetlb.h>
  #include <linux/shm.h>
  #include <linux/init.h>
  #include <linux/file.h>
  #include <linux/mman.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
  #include <linux/shmem_fs.h>
  #include <linux/security.h>
  #include <linux/syscalls.h>
  #include <linux/audit.h>
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
34
  #include <linux/capability.h>
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
35
  #include <linux/ptrace.h>
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
36
  #include <linux/seq_file.h>
3e148c799   Nadia Derbey   fix idr_find() lo...
37
  #include <linux/rwsem.h>
4e9823111   Kirill Korotaev   [PATCH] IPC names...
38
  #include <linux/nsproxy.h>
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
39
  #include <linux/mount.h>
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
40
  #include <linux/ipc_namespace.h>
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
41

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
43
44
  #include <asm/uaccess.h>
  
  #include "util.h"
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
45
46
47
48
49
50
51
52
  struct shm_file_data {
  	int id;
  	struct ipc_namespace *ns;
  	struct file *file;
  	const struct vm_operations_struct *vm_ops;
  };
  
  #define shm_file_data(file) (*((struct shm_file_data **)&(file)->private_data))
9a32144e9   Arjan van de Ven   [PATCH] mark stru...
53
  static const struct file_operations shm_file_operations;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  static struct vm_operations_struct shm_vm_ops;
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
55
  #define shm_ids(ns)	((ns)->ids[IPC_SHM_IDS])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56

4e9823111   Kirill Korotaev   [PATCH] IPC names...
57
58
  #define shm_unlock(shp)			\
  	ipc_unlock(&(shp)->shm_perm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59

7748dbfaa   Nadia Derbey   ipc: unify the sy...
60
  static int newseg(struct ipc_namespace *, struct ipc_params *);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
61
62
  static void shm_open(struct vm_area_struct *vma);
  static void shm_close(struct vm_area_struct *vma);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
63
  static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
65
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
  #endif
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
67
  void shm_init_ns(struct ipc_namespace *ns)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
68
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
69
70
71
72
  	ns->shm_ctlmax = SHMMAX;
  	ns->shm_ctlall = SHMALL;
  	ns->shm_ctlmni = SHMMNI;
  	ns->shm_tot = 0;
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
73
  	ipc_init_ids(&ns->ids[IPC_SHM_IDS]);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
74
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
75
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
76
77
   * Called with shm_ids.rw_mutex (writer) and the shp structure locked.
   * Only shm_ids.rw_mutex remains locked on exit.
f4566f048   Nadia Derbey   ipc: fix wrong co...
78
   */
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
79
  static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
80
  {
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
81
82
  	struct shmid_kernel *shp;
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
83
84
85
86
87
88
89
90
  	if (shp->shm_nattch){
  		shp->shm_perm.mode |= SHM_DEST;
  		/* Do not find it any more */
  		shp->shm_perm.key = IPC_PRIVATE;
  		shm_unlock(shp);
  	} else
  		shm_destroy(ns, shp);
  }
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
91
  #ifdef CONFIG_IPC_NS
4e9823111   Kirill Korotaev   [PATCH] IPC names...
92
93
  void shm_exit_ns(struct ipc_namespace *ns)
  {
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
94
  	free_ipcs(ns, &shm_ids(ns), do_shm_rmid);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
95
  }
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
96
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
  
  void __init shm_init (void)
  {
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
100
  	shm_init_ns(&init_ipc_ns);
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
101
102
103
  	ipc_init_proc_interface("sysvipc/shm",
  				"       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime
  ",
4e9823111   Kirill Korotaev   [PATCH] IPC names...
104
  				IPC_SHM_IDS, sysvipc_shm_proc_show);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  }
3e148c799   Nadia Derbey   fix idr_find() lo...
106
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
107
   * shm_lock_(check_) routines are called in the paths where the rw_mutex
00c2bf85d   Nadia Derbey   ipc: get rid of i...
108
   * is not necessarily held.
3e148c799   Nadia Derbey   fix idr_find() lo...
109
   */
023a53557   Nadia Derbey   ipc: integrate ip...
110
  static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
  {
03f02c765   Nadia Derbey   Storing ipcs into...
112
  	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
b1ed88b47   Pierre Peiffer   IPC: fix error ch...
113
114
  	if (IS_ERR(ipcp))
  		return (struct shmid_kernel *)ipcp;
03f02c765   Nadia Derbey   Storing ipcs into...
115
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
023a53557   Nadia Derbey   ipc: integrate ip...
116
117
118
119
120
  }
  
  static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
  						int id)
  {
03f02c765   Nadia Derbey   Storing ipcs into...
121
  	struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
b1ed88b47   Pierre Peiffer   IPC: fix error ch...
122
123
  	if (IS_ERR(ipcp))
  		return (struct shmid_kernel *)ipcp;
03f02c765   Nadia Derbey   Storing ipcs into...
124
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  }
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
126
  static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
128
  	ipc_rmid(&shm_ids(ns), &s->shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
131
132
  /* This is called by fork, once for every shm attach. */
  static void shm_open(struct vm_area_struct *vma)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
133
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
134
135
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
137
  	shp = shm_lock(sfd->ns, sfd->id);
023a53557   Nadia Derbey   ipc: integrate ip...
138
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  	shp->shm_atim = get_seconds();
b488893a3   Pavel Emelyanov   pid namespaces: c...
140
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
143
  	shp->shm_nattch++;
  	shm_unlock(shp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
  /*
   * shm_destroy - free the struct shmid_kernel
   *
f4566f048   Nadia Derbey   ipc: fix wrong co...
147
   * @ns: namespace
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
   * @shp: struct to free
   *
3e148c799   Nadia Derbey   fix idr_find() lo...
150
   * It has to be called with shp and shm_ids.rw_mutex (writer) locked,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
   * but returns with shp unlocked and freed.
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
153
  static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
155
  	ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
156
  	shm_rmid(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
158
159
160
  	shm_unlock(shp);
  	if (!is_file_hugepages(shp->shm_file))
  		shmem_lock(shp->shm_file, 0, shp->mlock_user);
  	else
6d63079ad   Josef Sipek   [PATCH] struct pa...
161
  		user_shm_unlock(shp->shm_file->f_path.dentry->d_inode->i_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
165
166
167
168
  						shp->mlock_user);
  	fput (shp->shm_file);
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  }
  
  /*
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
169
   * remove the attach descriptor vma.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
   * free memory for segment if it is marked destroyed.
   * The descriptor has already been removed from the current->mm->mmap list
   * and will later be kfree()d.
   */
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
174
  static void shm_close(struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
176
177
  	struct file * file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
179
  	struct ipc_namespace *ns = sfd->ns;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
180

3e148c799   Nadia Derbey   fix idr_find() lo...
181
  	down_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  	/* remove from the list of attaches of the shm segment */
00c2bf85d   Nadia Derbey   ipc: get rid of i...
183
  	shp = shm_lock(ns, sfd->id);
023a53557   Nadia Derbey   ipc: integrate ip...
184
  	BUG_ON(IS_ERR(shp));
b488893a3   Pavel Emelyanov   pid namespaces: c...
185
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
  	shp->shm_dtim = get_seconds();
  	shp->shm_nattch--;
  	if(shp->shm_nattch == 0 &&
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
189
  	   shp->shm_perm.mode & SHM_DEST)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
190
  		shm_destroy(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
192
  	else
  		shm_unlock(shp);
3e148c799   Nadia Derbey   fix idr_find() lo...
193
  	up_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
194
  }
d0217ac04   Nick Piggin   mm: fault feedbac...
195
  static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
196
197
198
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
d0217ac04   Nick Piggin   mm: fault feedbac...
199
  	return sfd->vm_ops->fault(vma, vmf);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
200
201
202
  }
  
  #ifdef CONFIG_NUMA
d823e3e75   Adrian Bunk   ipc/shm.c: make 2...
203
  static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
204
205
206
207
208
209
210
211
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
  	int err = 0;
  	if (sfd->vm_ops->set_policy)
  		err = sfd->vm_ops->set_policy(vma, new);
  	return err;
  }
d823e3e75   Adrian Bunk   ipc/shm.c: make 2...
212
213
  static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
  					unsigned long addr)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
214
215
216
217
218
219
220
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
  	struct mempolicy *pol = NULL;
  
  	if (sfd->vm_ops->get_policy)
  		pol = sfd->vm_ops->get_policy(vma, addr);
52cd3b074   Lee Schermerhorn   mempolicy: rework...
221
  	else if (vma->vm_policy)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
222
  		pol = vma->vm_policy;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
223

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
224
225
226
  	return pol;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
  static int shm_mmap(struct file * file, struct vm_area_struct * vma)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
229
  	struct shm_file_data *sfd = shm_file_data(file);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
230
  	int ret;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
231
232
233
234
  	ret = sfd->file->f_op->mmap(sfd->file, vma);
  	if (ret != 0)
  		return ret;
  	sfd->vm_ops = vma->vm_ops;
2e92a3bae   David Howells   NOMMU: Fix SYSV I...
235
  #ifdef CONFIG_MMU
54cb8821d   Nick Piggin   mm: merge populat...
236
  	BUG_ON(!sfd->vm_ops->fault);
2e92a3bae   David Howells   NOMMU: Fix SYSV I...
237
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
238
239
  	vma->vm_ops = &shm_vm_ops;
  	shm_open(vma);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
240
241
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
243
244
  static int shm_release(struct inode *ino, struct file *file)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
245
  	struct shm_file_data *sfd = shm_file_data(file);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
246

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
247
248
249
  	put_ipc_ns(sfd->ns);
  	shm_file_data(file) = NULL;
  	kfree(sfd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
250
251
  	return 0;
  }
516dffdcd   Adam Litke   [PATCH] Fix get_u...
252
253
254
255
256
257
258
259
260
261
262
  static int shm_fsync(struct file *file, struct dentry *dentry, int datasync)
  {
  	int (*fsync) (struct file *, struct dentry *, int datasync);
  	struct shm_file_data *sfd = shm_file_data(file);
  	int ret = -EINVAL;
  
  	fsync = sfd->file->f_op->fsync;
  	if (fsync)
  		ret = fsync(sfd->file, sfd->file->f_path.dentry, datasync);
  	return ret;
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
263
264
265
266
267
  static unsigned long shm_get_unmapped_area(struct file *file,
  	unsigned long addr, unsigned long len, unsigned long pgoff,
  	unsigned long flags)
  {
  	struct shm_file_data *sfd = shm_file_data(file);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
268
269
270
271
272
273
274
275
276
277
278
279
280
  	return get_unmapped_area(sfd->file, addr, len, pgoff, flags);
  }
  
  int is_file_shm_hugepages(struct file *file)
  {
  	int ret = 0;
  
  	if (file->f_op == &shm_file_operations) {
  		struct shm_file_data *sfd;
  		sfd = shm_file_data(file);
  		ret = is_file_hugepages(sfd->file);
  	}
  	return ret;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
281
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
282

9a32144e9   Arjan van de Ven   [PATCH] mark stru...
283
  static const struct file_operations shm_file_operations = {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
284
  	.mmap		= shm_mmap,
516dffdcd   Adam Litke   [PATCH] Fix get_u...
285
  	.fsync		= shm_fsync,
4e9823111   Kirill Korotaev   [PATCH] IPC names...
286
  	.release	= shm_release,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
287
  	.get_unmapped_area	= shm_get_unmapped_area,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
292
  };
  
  static struct vm_operations_struct shm_vm_ops = {
  	.open	= shm_open,	/* callback for a new vm-area open */
  	.close	= shm_close,	/* callback for when the vm-area is released */
54cb8821d   Nick Piggin   mm: merge populat...
293
  	.fault	= shm_fault,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
294
295
296
  #if defined(CONFIG_NUMA)
  	.set_policy = shm_set_policy,
  	.get_policy = shm_get_policy,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
  #endif
  };
f4566f048   Nadia Derbey   ipc: fix wrong co...
299
300
301
302
303
  /**
   * newseg - Create a new shared memory segment
   * @ns: namespace
   * @params: ptr to the structure that contains key, size and shmflg
   *
3e148c799   Nadia Derbey   fix idr_find() lo...
304
   * Called with shm_ids.rw_mutex held as a writer.
f4566f048   Nadia Derbey   ipc: fix wrong co...
305
   */
7748dbfaa   Nadia Derbey   ipc: unify the sy...
306
  static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  {
7748dbfaa   Nadia Derbey   ipc: unify the sy...
308
309
310
  	key_t key = params->key;
  	int shmflg = params->flg;
  	size_t size = params->u.size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
315
316
  	int error;
  	struct shmid_kernel *shp;
  	int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
  	struct file * file;
  	char name[13];
  	int id;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
317
  	if (size < SHMMIN || size > ns->shm_ctlmax)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
  		return -EINVAL;
f66d45e99   Guy Streeter   [PATCH] correct s...
319
  	if (ns->shm_tot + numpages > ns->shm_ctlall)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
321
322
323
324
325
326
  		return -ENOSPC;
  
  	shp = ipc_rcu_alloc(sizeof(*shp));
  	if (!shp)
  		return -ENOMEM;
  
  	shp->shm_perm.key = key;
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
327
  	shp->shm_perm.mode = (shmflg & S_IRWXUGO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
332
333
334
335
  	shp->mlock_user = NULL;
  
  	shp->shm_perm.security = NULL;
  	error = security_shm_alloc(shp);
  	if (error) {
  		ipc_rcu_putref(shp);
  		return error;
  	}
9d66586f7   Eric W. Biederman   shm: fix the file...
336
  	sprintf (name, "SYSV%08x", key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  	if (shmflg & SHM_HUGETLB) {
9d66586f7   Eric W. Biederman   shm: fix the file...
338
339
  		/* hugetlb_file_setup takes care of mlock user accounting */
  		file = hugetlb_file_setup(name, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
340
341
  		shp->mlock_user = current->user;
  	} else {
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
342
343
344
345
346
347
348
349
  		int acctflag = VM_ACCOUNT;
  		/*
  		 * Do not allow no accounting for OVERCOMMIT_NEVER, even
  	 	 * if it's asked for.
  		 */
  		if  ((shmflg & SHM_NORESERVE) &&
  				sysctl_overcommit_memory != OVERCOMMIT_NEVER)
  			acctflag = 0;
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
350
  		file = shmem_file_setup(name, size, acctflag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
352
353
354
  	}
  	error = PTR_ERR(file);
  	if (IS_ERR(file))
  		goto no_file;
48dea404e   Pierre Peiffer   IPC: use ipc_buil...
355
  	id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
283bb7fad   Pierre Peiffer   IPC: fix error ca...
356
357
  	if (id < 0) {
  		error = id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  		goto no_id;
283bb7fad   Pierre Peiffer   IPC: fix error ca...
359
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360

b488893a3   Pavel Emelyanov   pid namespaces: c...
361
  	shp->shm_cprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
  	shp->shm_lprid = 0;
  	shp->shm_atim = shp->shm_dtim = 0;
  	shp->shm_ctim = get_seconds();
  	shp->shm_segsz = size;
  	shp->shm_nattch = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  	shp->shm_file = file;
30475cc12   Badari Pulavarty   Restore shmid as ...
368
369
370
371
  	/*
  	 * shmid gets reported as "inode#" in /proc/pid/maps.
  	 * proc-ps tools use this. Changing this will break them.
  	 */
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
372
  	file->f_dentry->d_inode->i_ino = shp->shm_perm.id;
551110a94   Krishnakumar R   [PATCH] hugetlb: ...
373

4e9823111   Kirill Korotaev   [PATCH] IPC names...
374
  	ns->shm_tot += numpages;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
375
  	error = shp->shm_perm.id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  	shm_unlock(shp);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
377
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
382
383
384
385
  
  no_id:
  	fput(file);
  no_file:
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  	return error;
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
386
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
387
   * Called with shm_ids.rw_mutex and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
388
   */
03f02c765   Nadia Derbey   Storing ipcs into...
389
  static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
390
  {
03f02c765   Nadia Derbey   Storing ipcs into...
391
392
393
394
  	struct shmid_kernel *shp;
  
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
  	return security_shm_associate(shp, shmflg);
7748dbfaa   Nadia Derbey   ipc: unify the sy...
395
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
396
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
397
   * Called with shm_ids.rw_mutex and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
398
   */
03f02c765   Nadia Derbey   Storing ipcs into...
399
400
  static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
  				struct ipc_params *params)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
401
  {
03f02c765   Nadia Derbey   Storing ipcs into...
402
403
404
405
  	struct shmid_kernel *shp;
  
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
  	if (shp->shm_segsz < params->u.size)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
406
407
408
409
  		return -EINVAL;
  
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
411
  asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
412
  	struct ipc_namespace *ns;
7748dbfaa   Nadia Derbey   ipc: unify the sy...
413
414
  	struct ipc_ops shm_ops;
  	struct ipc_params shm_params;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
415
416
  
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417

7748dbfaa   Nadia Derbey   ipc: unify the sy...
418
419
420
  	shm_ops.getnew = newseg;
  	shm_ops.associate = shm_security;
  	shm_ops.more_checks = shm_more_checks;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
421

7748dbfaa   Nadia Derbey   ipc: unify the sy...
422
423
424
  	shm_params.key = key;
  	shm_params.flg = shmflg;
  	shm_params.u.size = size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425

7748dbfaa   Nadia Derbey   ipc: unify the sy...
426
  	return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  }
  
  static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version)
  {
  	switch(version) {
  	case IPC_64:
  		return copy_to_user(buf, in, sizeof(*in));
  	case IPC_OLD:
  	    {
  		struct shmid_ds out;
  
  		ipc64_perm_to_ipc_perm(&in->shm_perm, &out.shm_perm);
  		out.shm_segsz	= in->shm_segsz;
  		out.shm_atime	= in->shm_atime;
  		out.shm_dtime	= in->shm_dtime;
  		out.shm_ctime	= in->shm_ctime;
  		out.shm_cpid	= in->shm_cpid;
  		out.shm_lpid	= in->shm_lpid;
  		out.shm_nattch	= in->shm_nattch;
  
  		return copy_to_user(buf, &out, sizeof(out));
  	    }
  	default:
  		return -EINVAL;
  	}
  }
016d7132f   Pierre Peiffer   IPC: get rid of t...
453
454
  static inline unsigned long
  copy_shmid_from_user(struct shmid64_ds *out, void __user *buf, int version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
  {
  	switch(version) {
  	case IPC_64:
016d7132f   Pierre Peiffer   IPC: get rid of t...
458
  		if (copy_from_user(out, buf, sizeof(*out)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
  	case IPC_OLD:
  	    {
  		struct shmid_ds tbuf_old;
  
  		if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
  			return -EFAULT;
016d7132f   Pierre Peiffer   IPC: get rid of t...
467
468
469
  		out->shm_perm.uid	= tbuf_old.shm_perm.uid;
  		out->shm_perm.gid	= tbuf_old.shm_perm.gid;
  		out->shm_perm.mode	= tbuf_old.shm_perm.mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
  
  		return 0;
  	    }
  	default:
  		return -EINVAL;
  	}
  }
  
  static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version)
  {
  	switch(version) {
  	case IPC_64:
  		return copy_to_user(buf, in, sizeof(*in));
  	case IPC_OLD:
  	    {
  		struct shminfo out;
  
  		if(in->shmmax > INT_MAX)
  			out.shmmax = INT_MAX;
  		else
  			out.shmmax = (int)in->shmmax;
  
  		out.shmmin	= in->shmmin;
  		out.shmmni	= in->shmmni;
  		out.shmseg	= in->shmseg;
  		out.shmall	= in->shmall; 
  
  		return copy_to_user(buf, &out, sizeof(out));
  	    }
  	default:
  		return -EINVAL;
  	}
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
503
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
504
   * Called with shm_ids.rw_mutex held as a reader
f4566f048   Nadia Derbey   ipc: fix wrong co...
505
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
506
507
  static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
  		unsigned long *swp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
509
510
  	int next_id;
  	int total, in_use;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
  
  	*rss = 0;
  	*swp = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
514
515
516
  	in_use = shm_ids(ns).in_use;
  
  	for (total = 0, next_id = 0; total < in_use; next_id++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
  		struct shmid_kernel *shp;
  		struct inode *inode;
637c36634   Nadia Derbey   ipc: remove the i...
519
  		shp = idr_find(&shm_ids(ns).ipcs_idr, next_id);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
520
  		if (shp == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
  			continue;
6d63079ad   Josef Sipek   [PATCH] struct pa...
522
  		inode = shp->shm_file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
  
  		if (is_file_hugepages(shp->shm_file)) {
  			struct address_space *mapping = inode->i_mapping;
a55164389   Andi Kleen   hugetlb: modular ...
526
527
  			struct hstate *h = hstate_file(shp->shm_file);
  			*rss += pages_per_huge_page(h) * mapping->nrpages;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
531
532
533
534
  		} else {
  			struct shmem_inode_info *info = SHMEM_I(inode);
  			spin_lock(&info->lock);
  			*rss += inode->i_mapping->nrpages;
  			*swp += info->swapped;
  			spin_unlock(&info->lock);
  		}
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
535
536
  
  		total++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
  	}
  }
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
539
540
541
542
543
544
545
  /*
   * This function handles some shmctl commands which require the rw_mutex
   * to be held in write mode.
   * NOTE: no locks must be held, the rw_mutex is taken inside this function.
   */
  static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
  		       struct shmid_ds __user *buf, int version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
  {
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
547
  	struct kern_ipc_perm *ipcp;
016d7132f   Pierre Peiffer   IPC: get rid of t...
548
  	struct shmid64_ds shmid64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  	struct shmid_kernel *shp;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
550
551
552
  	int err;
  
  	if (cmd == IPC_SET) {
016d7132f   Pierre Peiffer   IPC: get rid of t...
553
  		if (copy_shmid_from_user(&shmid64, buf, version))
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
554
555
  			return -EFAULT;
  	}
a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
556
557
558
  	ipcp = ipcctl_pre_down(&shm_ids(ns), shmid, cmd, &shmid64.shm_perm, 0);
  	if (IS_ERR(ipcp))
  		return PTR_ERR(ipcp);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
559

a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
560
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
561
562
563
564
565
566
567
568
569
  
  	err = security_shm_shmctl(shp, cmd);
  	if (err)
  		goto out_unlock;
  	switch (cmd) {
  	case IPC_RMID:
  		do_shm_rmid(ns, ipcp);
  		goto out_up;
  	case IPC_SET:
8f4a3809c   Pierre Peiffer   IPC: introduce ip...
570
  		ipc_update_perm(&shmid64.shm_perm, ipcp);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
  		shp->shm_ctim = get_seconds();
  		break;
  	default:
  		err = -EINVAL;
  	}
  out_unlock:
  	shm_unlock(shp);
  out_up:
  	up_write(&shm_ids(ns).rw_mutex);
  	return err;
  }
  
  asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf)
  {
  	struct shmid_kernel *shp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
586
  	int err, version;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
587
  	struct ipc_namespace *ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
591
592
593
594
  
  	if (cmd < 0 || shmid < 0) {
  		err = -EINVAL;
  		goto out;
  	}
  
  	version = ipc_parse_version(&cmd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
595
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
597
598
599
600
601
602
603
604
605
606
  
  	switch (cmd) { /* replace with proc interface ? */
  	case IPC_INFO:
  	{
  		struct shminfo64 shminfo;
  
  		err = security_shm_shmctl(NULL, cmd);
  		if (err)
  			return err;
  
  		memset(&shminfo,0,sizeof(shminfo));
4e9823111   Kirill Korotaev   [PATCH] IPC names...
607
608
609
  		shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni;
  		shminfo.shmmax = ns->shm_ctlmax;
  		shminfo.shmall = ns->shm_ctlall;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
610
611
612
613
  
  		shminfo.shmmin = SHMMIN;
  		if(copy_shminfo_to_user (buf, &shminfo, version))
  			return -EFAULT;
f4566f048   Nadia Derbey   ipc: fix wrong co...
614

3e148c799   Nadia Derbey   fix idr_find() lo...
615
  		down_read(&shm_ids(ns).rw_mutex);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
616
  		err = ipc_get_maxid(&shm_ids(ns));
3e148c799   Nadia Derbey   fix idr_find() lo...
617
  		up_read(&shm_ids(ns).rw_mutex);
f4566f048   Nadia Derbey   ipc: fix wrong co...
618

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
620
621
622
623
624
625
626
627
628
629
630
631
  		if(err<0)
  			err = 0;
  		goto out;
  	}
  	case SHM_INFO:
  	{
  		struct shm_info shm_info;
  
  		err = security_shm_shmctl(NULL, cmd);
  		if (err)
  			return err;
  
  		memset(&shm_info,0,sizeof(shm_info));
3e148c799   Nadia Derbey   fix idr_find() lo...
632
  		down_read(&shm_ids(ns).rw_mutex);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
633
634
635
  		shm_info.used_ids = shm_ids(ns).in_use;
  		shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp);
  		shm_info.shm_tot = ns->shm_tot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
  		shm_info.swap_attempts = 0;
  		shm_info.swap_successes = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
638
  		err = ipc_get_maxid(&shm_ids(ns));
3e148c799   Nadia Derbey   fix idr_find() lo...
639
  		up_read(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
641
642
643
644
645
646
647
648
649
650
651
652
  		if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
  			err = -EFAULT;
  			goto out;
  		}
  
  		err = err < 0 ? 0 : err;
  		goto out;
  	}
  	case SHM_STAT:
  	case IPC_STAT:
  	{
  		struct shmid64_ds tbuf;
  		int result;
023a53557   Nadia Derbey   ipc: integrate ip...
653
654
655
  
  		if (!buf) {
  			err = -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
  			goto out;
023a53557   Nadia Derbey   ipc: integrate ip...
657
658
659
660
661
662
663
664
  		}
  
  		if (cmd == SHM_STAT) {
  			shp = shm_lock(ns, shmid);
  			if (IS_ERR(shp)) {
  				err = PTR_ERR(shp);
  				goto out;
  			}
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
665
  			result = shp->shm_perm.id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
  		} else {
023a53557   Nadia Derbey   ipc: integrate ip...
667
668
669
670
671
  			shp = shm_lock_check(ns, shmid);
  			if (IS_ERR(shp)) {
  				err = PTR_ERR(shp);
  				goto out;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
672
673
674
675
676
677
678
679
  			result = 0;
  		}
  		err=-EACCES;
  		if (ipcperms (&shp->shm_perm, S_IRUGO))
  			goto out_unlock;
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock;
023a53557   Nadia Derbey   ipc: integrate ip...
680
  		memset(&tbuf, 0, sizeof(tbuf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
683
684
685
686
687
  		kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
  		tbuf.shm_segsz	= shp->shm_segsz;
  		tbuf.shm_atime	= shp->shm_atim;
  		tbuf.shm_dtime	= shp->shm_dtim;
  		tbuf.shm_ctime	= shp->shm_ctim;
  		tbuf.shm_cpid	= shp->shm_cprid;
  		tbuf.shm_lpid	= shp->shm_lprid;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
688
  		tbuf.shm_nattch	= shp->shm_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
691
692
693
694
695
696
697
698
  		shm_unlock(shp);
  		if(copy_shmid_to_user (buf, &tbuf, version))
  			err = -EFAULT;
  		else
  			err = result;
  		goto out;
  	}
  	case SHM_LOCK:
  	case SHM_UNLOCK:
  	{
023a53557   Nadia Derbey   ipc: integrate ip...
699
700
701
  		shp = shm_lock_check(ns, shmid);
  		if (IS_ERR(shp)) {
  			err = PTR_ERR(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704

073115d6b   Steve Grubb   [PATCH] Rework of...
705
706
707
  		err = audit_ipc_obj(&(shp->shm_perm));
  		if (err)
  			goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
  		if (!capable(CAP_IPC_LOCK)) {
  			err = -EPERM;
  			if (current->euid != shp->shm_perm.uid &&
  			    current->euid != shp->shm_perm.cuid)
  				goto out_unlock;
  			if (cmd == SHM_LOCK &&
  			    !current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur)
  				goto out_unlock;
  		}
  
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock;
  		
  		if(cmd==SHM_LOCK) {
  			struct user_struct * user = current->user;
  			if (!is_file_hugepages(shp->shm_file)) {
  				err = shmem_lock(shp->shm_file, 1, user);
7be77e20d   Pavel Emelianov   Fix user struct l...
726
  				if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
727
  					shp->shm_perm.mode |= SHM_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
729
730
731
732
  					shp->mlock_user = user;
  				}
  			}
  		} else if (!is_file_hugepages(shp->shm_file)) {
  			shmem_lock(shp->shm_file, 0, shp->mlock_user);
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
733
  			shp->shm_perm.mode &= ~SHM_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
736
737
738
739
  			shp->mlock_user = NULL;
  		}
  		shm_unlock(shp);
  		goto out;
  	}
  	case IPC_RMID:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
  	case IPC_SET:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
741
742
  		err = shmctl_down(ns, shmid, cmd, buf, version);
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
743
  	default:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
744
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
  out_unlock:
  	shm_unlock(shp);
  out:
  	return err;
  }
  
  /*
   * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
   *
   * NOTE! Despite the name, this is NOT a direct system call entrypoint. The
   * "raddr" thing points to kernel space, and there has to be a wrapper around
   * this.
   */
  long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
  {
  	struct shmid_kernel *shp;
  	unsigned long addr;
  	unsigned long size;
  	struct file * file;
  	int    err;
  	unsigned long flags;
  	unsigned long prot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  	int acc_mode;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
769
  	unsigned long user_addr;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
770
  	struct ipc_namespace *ns;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
771
772
773
  	struct shm_file_data *sfd;
  	struct path path;
  	mode_t f_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
775
776
  	err = -EINVAL;
  	if (shmid < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
  		goto out;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
778
  	else if ((addr = (ulong)shmaddr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
781
782
783
784
785
  		if (addr & (SHMLBA-1)) {
  			if (shmflg & SHM_RND)
  				addr &= ~(SHMLBA-1);	   /* round down */
  			else
  #ifndef __ARCH_FORCE_SHMLBA
  				if (addr & ~PAGE_MASK)
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
786
  					goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
788
789
790
  		}
  		flags = MAP_SHARED | MAP_FIXED;
  	} else {
  		if ((shmflg & SHM_REMAP))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
791
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
796
797
  
  		flags = MAP_SHARED;
  	}
  
  	if (shmflg & SHM_RDONLY) {
  		prot = PROT_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  		acc_mode = S_IRUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
799
  		f_mode = FMODE_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
801
  	} else {
  		prot = PROT_READ | PROT_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  		acc_mode = S_IRUGO | S_IWUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
803
  		f_mode = FMODE_READ | FMODE_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
807
808
809
810
811
812
813
  	}
  	if (shmflg & SHM_EXEC) {
  		prot |= PROT_EXEC;
  		acc_mode |= S_IXUGO;
  	}
  
  	/*
  	 * We cannot rely on the fs check since SYSV IPC does have an
  	 * additional creator id...
  	 */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
814
  	ns = current->nsproxy->ipc_ns;
023a53557   Nadia Derbey   ipc: integrate ip...
815
816
817
  	shp = shm_lock_check(ns, shmid);
  	if (IS_ERR(shp)) {
  		err = PTR_ERR(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
  		goto out;
023a53557   Nadia Derbey   ipc: integrate ip...
819
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
820
821
822
823
  
  	err = -EACCES;
  	if (ipcperms(&shp->shm_perm, acc_mode))
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
825
  
  	err = security_shm_shmat(shp, shmaddr, shmflg);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
826
827
828
829
  	if (err)
  		goto out_unlock;
  
  	path.dentry = dget(shp->shm_file->f_path.dentry);
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
830
  	path.mnt    = shp->shm_file->f_path.mnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
  	shp->shm_nattch++;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
832
  	size = i_size_read(path.dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
  	shm_unlock(shp);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
834
835
836
  	err = -ENOMEM;
  	sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
  	if (!sfd)
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
837
  		goto out_put_dentry;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
838

ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
839
  	file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
840
841
  	if (!file)
  		goto out_free;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
842
  	file->private_data = sfd;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
843
  	file->f_mapping = shp->shm_file->f_mapping;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
844
  	sfd->id = shp->shm_perm.id;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
845
846
847
  	sfd->ns = get_ipc_ns(ns);
  	sfd->file = shp->shm_file;
  	sfd->vm_ops = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
  	down_write(&current->mm->mmap_sem);
  	if (addr && !(shmflg & SHM_REMAP)) {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
850
  		err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
852
853
854
855
856
857
858
859
860
861
  		if (find_vma_intersection(current->mm, addr, addr + size))
  			goto invalid;
  		/*
  		 * If shm segment goes below stack, make sure there is some
  		 * space left for the stack to grow (at least 4 pages).
  		 */
  		if (addr < current->mm->start_stack &&
  		    addr > current->mm->start_stack - size - PAGE_SIZE * 5)
  			goto invalid;
  	}
  		
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
862
863
864
865
866
  	user_addr = do_mmap (file, addr, size, prot, flags, 0);
  	*raddr = user_addr;
  	err = 0;
  	if (IS_ERR_VALUE(user_addr))
  		err = (long)user_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
868
  invalid:
  	up_write(&current->mm->mmap_sem);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
869
870
871
  	fput(file);
  
  out_nattch:
3e148c799   Nadia Derbey   fix idr_find() lo...
872
  	down_write(&shm_ids(ns).rw_mutex);
00c2bf85d   Nadia Derbey   ipc: get rid of i...
873
  	shp = shm_lock(ns, shmid);
023a53557   Nadia Derbey   ipc: integrate ip...
874
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
876
  	shp->shm_nattch--;
  	if(shp->shm_nattch == 0 &&
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
877
  	   shp->shm_perm.mode & SHM_DEST)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
878
  		shm_destroy(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
879
880
  	else
  		shm_unlock(shp);
3e148c799   Nadia Derbey   fix idr_find() lo...
881
  	up_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
884
  out:
  	return err;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
885
886
887
888
889
890
891
  
  out_unlock:
  	shm_unlock(shp);
  	goto out;
  
  out_free:
  	kfree(sfd);
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
892
  out_put_dentry:
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
893
  	dput(path.dentry);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
894
  	goto out_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
  }
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
896
897
898
899
900
901
902
903
904
905
906
  asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg)
  {
  	unsigned long ret;
  	long err;
  
  	err = do_shmat(shmid, shmaddr, shmflg, &ret);
  	if (err)
  		return err;
  	force_successful_syscall_return();
  	return (long)ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
908
909
910
911
912
913
914
915
916
917
  /*
   * detach and kill segment if marked destroyed.
   * The work is done in shm_close.
   */
  asmlinkage long sys_shmdt(char __user *shmaddr)
  {
  	struct mm_struct *mm = current->mm;
  	struct vm_area_struct *vma, *next;
  	unsigned long addr = (unsigned long)shmaddr;
  	loff_t size = 0;
  	int retval = -EINVAL;
df1e2fb54   Hugh Dickins   [PATCH] shmdt: ch...
918
919
  	if (addr & ~PAGE_MASK)
  		return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
  	down_write(&mm->mmap_sem);
  
  	/*
  	 * This function tries to be smart and unmap shm segments that
  	 * were modified by partial mlock or munmap calls:
  	 * - It first determines the size of the shm segment that should be
  	 *   unmapped: It searches for a vma that is backed by shm and that
  	 *   started at address shmaddr. It records it's size and then unmaps
  	 *   it.
  	 * - Then it unmaps all shm vmas that started at shmaddr and that
  	 *   are within the initially determined size.
  	 * Errors from do_munmap are ignored: the function only fails if
  	 * it's called with invalid parameters or if it's called to unmap
  	 * a part of a vma. Both calls in this function are for full vmas,
  	 * the parameters are directly copied from the vma itself and always
  	 * valid - therefore do_munmap cannot fail. (famous last words?)
  	 */
  	/*
  	 * If it had been mremap()'d, the starting address would not
  	 * match the usual checks anyway. So assume all vma's are
  	 * above the starting address given.
  	 */
  	vma = find_vma(mm, addr);
  
  	while (vma) {
  		next = vma->vm_next;
  
  		/*
  		 * Check if the starting address would match, i.e. it's
  		 * a fragment created by mprotect() and/or munmap(), or it
  		 * otherwise it starts at this address with no hassles.
  		 */
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
952
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
6d63079ad   Josef Sipek   [PATCH] struct pa...
954
  			size = vma->vm_file->f_path.dentry->d_inode->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
  			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
  			/*
  			 * We discovered the size of the shm segment, so
  			 * break out of here and fall through to the next
  			 * loop that uses the size information to stop
  			 * searching for matching vma's.
  			 */
  			retval = 0;
  			vma = next;
  			break;
  		}
  		vma = next;
  	}
  
  	/*
  	 * We need look no further than the maximum address a fragment
  	 * could possibly have landed at. Also cast things to loff_t to
  	 * prevent overflows and make comparisions vs. equal-width types.
  	 */
8e36709d8   KAMEZAWA Hiroyuki   [PATCH] shmdt can...
974
  	size = PAGE_ALIGN(size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
976
977
978
  	while (vma && (loff_t)(vma->vm_end - addr) <= size) {
  		next = vma->vm_next;
  
  		/* finding a matching vma now does not alter retval */
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
979
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980
981
982
983
984
985
986
987
988
989
990
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
  
  			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
  		vma = next;
  	}
  
  	up_write(&mm->mmap_sem);
  	return retval;
  }
  
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
991
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
992
  {
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
993
  	struct shmid_kernel *shp = it;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994

6c826818f   Paul Menage   /proc/sysvipc/shm...
995
996
997
998
999
  #if BITS_PER_LONG <= 32
  #define SIZE_SPEC "%10lu"
  #else
  #define SIZE_SPEC "%21lu"
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000

6c826818f   Paul Menage   /proc/sysvipc/shm...
1001
1002
1003
1004
  	return seq_printf(s,
  			  "%10d %10d  %4o " SIZE_SPEC " %5u %5u  "
  			  "%5lu %5u %5u %5u %5u %10lu %10lu %10lu
  ",
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1005
  			  shp->shm_perm.key,
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
1006
  			  shp->shm_perm.id,
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
1007
  			  shp->shm_perm.mode,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1008
1009
1010
  			  shp->shm_segsz,
  			  shp->shm_cprid,
  			  shp->shm_lprid,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1011
  			  shp->shm_nattch,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1012
1013
1014
1015
1016
1017
1018
  			  shp->shm_perm.uid,
  			  shp->shm_perm.gid,
  			  shp->shm_perm.cuid,
  			  shp->shm_perm.cgid,
  			  shp->shm_atim,
  			  shp->shm_dtim,
  			  shp->shm_ctim);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1019
1020
  }
  #endif