Blame view

ipc/shm.c 30.4 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;
f0f37e2f7   Alexey Dobriyan   const: mark struc...
54
  static const struct vm_operations_struct shm_vm_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55

ed2ddbf88   Pierre Peiffer   IPC: make struct ...
56
  #define shm_ids(ns)	((ns)->ids[IPC_SHM_IDS])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

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

7748dbfaa   Nadia Derbey   ipc: unify the sy...
61
  static int newseg(struct ipc_namespace *, struct ipc_params *);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
62
63
  static void shm_open(struct vm_area_struct *vma);
  static void shm_close(struct vm_area_struct *vma);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
64
  static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
66
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
  #endif
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
68
  void shm_init_ns(struct ipc_namespace *ns)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
69
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
70
71
72
  	ns->shm_ctlmax = SHMMAX;
  	ns->shm_ctlall = SHMALL;
  	ns->shm_ctlmni = SHMMNI;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
73
  	ns->shm_rmid_forced = 0;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
74
  	ns->shm_tot = 0;
e8148f758   WANG Cong   ipc: clean up ipc...
75
  	ipc_init_ids(&shm_ids(ns));
4e9823111   Kirill Korotaev   [PATCH] IPC names...
76
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
77
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
78
79
   * 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...
80
   */
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
81
  static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
82
  {
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
83
84
  	struct shmid_kernel *shp;
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
85
86
87
88
89
90
91
92
  	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 ...
93
  #ifdef CONFIG_IPC_NS
4e9823111   Kirill Korotaev   [PATCH] IPC names...
94
95
  void shm_exit_ns(struct ipc_namespace *ns)
  {
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
96
  	free_ipcs(ns, &shm_ids(ns), do_shm_rmid);
7d6feeb28   Serge E. Hallyn   ipc ns: fix memor...
97
  	idr_destroy(&ns->ids[IPC_SHM_IDS].ipcs_idr);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
98
  }
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
99
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100

140d0b210   Linus Torvalds   Do 'shm_init_ns()...
101
  static int __init ipc_ns_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
  {
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
103
  	shm_init_ns(&init_ipc_ns);
140d0b210   Linus Torvalds   Do 'shm_init_ns()...
104
105
106
107
108
109
110
  	return 0;
  }
  
  pure_initcall(ipc_ns_init);
  
  void __init shm_init (void)
  {
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
111
  	ipc_init_proc_interface("sysvipc/shm",
b79521807   Helge Deller   ipc/shm.c: add RS...
112
113
114
115
116
117
118
  #if BITS_PER_LONG <= 32
  				"       key      shmid perms       size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime        rss       swap
  ",
  #else
  				"       key      shmid perms                  size  cpid  lpid nattch   uid   gid  cuid  cgid      atime      dtime      ctime                   rss                  swap
  ",
  #endif
4e9823111   Kirill Korotaev   [PATCH] IPC names...
119
  				IPC_SHM_IDS, sysvipc_shm_proc_show);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  }
3e148c799   Nadia Derbey   fix idr_find() lo...
121
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
122
   * shm_lock_(check_) routines are called in the paths where the rw_mutex
00c2bf85d   Nadia Derbey   ipc: get rid of i...
123
   * is not necessarily held.
3e148c799   Nadia Derbey   fix idr_find() lo...
124
   */
023a53557   Nadia Derbey   ipc: integrate ip...
125
  static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  {
03f02c765   Nadia Derbey   Storing ipcs into...
127
  	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
b1ed88b47   Pierre Peiffer   IPC: fix error ch...
128
129
  	if (IS_ERR(ipcp))
  		return (struct shmid_kernel *)ipcp;
03f02c765   Nadia Derbey   Storing ipcs into...
130
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
023a53557   Nadia Derbey   ipc: integrate ip...
131
  }
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
132
133
134
  static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
  {
  	rcu_read_lock();
cf9d5d78d   Davidlohr Bueso   ipc: close open c...
135
  	ipc_lock_object(&ipcp->shm_perm);
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
136
  }
023a53557   Nadia Derbey   ipc: integrate ip...
137
138
139
  static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns,
  						int id)
  {
03f02c765   Nadia Derbey   Storing ipcs into...
140
  	struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id);
b1ed88b47   Pierre Peiffer   IPC: fix error ch...
141
142
  	if (IS_ERR(ipcp))
  		return (struct shmid_kernel *)ipcp;
03f02c765   Nadia Derbey   Storing ipcs into...
143
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  }
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
145
  static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
147
  	ipc_rmid(&shm_ids(ns), &s->shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
150
151
  /* 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...
152
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
153
154
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
156
  	shp = shm_lock(sfd->ns, sfd->id);
023a53557   Nadia Derbey   ipc: integrate ip...
157
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
  	shp->shm_atim = get_seconds();
b488893a3   Pavel Emelyanov   pid namespaces: c...
159
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
  	shp->shm_nattch++;
  	shm_unlock(shp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
  /*
   * shm_destroy - free the struct shmid_kernel
   *
f4566f048   Nadia Derbey   ipc: fix wrong co...
166
   * @ns: namespace
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
   * @shp: struct to free
   *
3e148c799   Nadia Derbey   fix idr_find() lo...
169
   * It has to be called with shp and shm_ids.rw_mutex (writer) locked,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
   * but returns with shp unlocked and freed.
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
172
  static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
174
  	ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
175
  	shm_rmid(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
  	shm_unlock(shp);
  	if (!is_file_hugepages(shp->shm_file))
  		shmem_lock(shp->shm_file, 0, shp->mlock_user);
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
179
  	else if (shp->mlock_user)
496ad9aa8   Al Viro   new helper: file_...
180
  		user_shm_unlock(file_inode(shp->shm_file)->i_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
185
186
187
  						shp->mlock_user);
  	fput (shp->shm_file);
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  }
  
  /*
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
   * shm_may_destroy - identifies whether shm segment should be destroyed now
   *
   * Returns true if and only if there are no active users of the segment and
   * one of the following is true:
   *
   * 1) shmctl(id, IPC_RMID, NULL) was called for this shp
   *
   * 2) sysctl kernel.shm_rmid_forced is set to 1.
   */
  static bool shm_may_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
  {
  	return (shp->shm_nattch == 0) &&
  	       (ns->shm_rmid_forced ||
  		(shp->shm_perm.mode & SHM_DEST));
  }
  
  /*
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
205
   * remove the attach descriptor vma.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
208
209
   * 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...
210
  static void shm_close(struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
212
213
  	struct file * file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
215
  	struct ipc_namespace *ns = sfd->ns;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
216

3e148c799   Nadia Derbey   fix idr_find() lo...
217
  	down_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
  	/* remove from the list of attaches of the shm segment */
00c2bf85d   Nadia Derbey   ipc: get rid of i...
219
  	shp = shm_lock(ns, sfd->id);
023a53557   Nadia Derbey   ipc: integrate ip...
220
  	BUG_ON(IS_ERR(shp));
b488893a3   Pavel Emelyanov   pid namespaces: c...
221
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
  	shp->shm_dtim = get_seconds();
  	shp->shm_nattch--;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
224
225
226
227
228
229
  	if (shm_may_destroy(ns, shp))
  		shm_destroy(ns, shp);
  	else
  		shm_unlock(shp);
  	up_write(&shm_ids(ns).rw_mutex);
  }
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
230
  /* Called with ns->shm_ids(ns).rw_mutex locked */
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
231
232
233
  static int shm_try_destroy_current(int id, void *p, void *data)
  {
  	struct ipc_namespace *ns = data;
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
234
235
  	struct kern_ipc_perm *ipcp = p;
  	struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
236

4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
237
  	if (shp->shm_creator != current)
5774ed014   Vasiliy Kulikov   shm: handle separ...
238
  		return 0;
5774ed014   Vasiliy Kulikov   shm: handle separ...
239
240
241
242
243
244
245
246
247
248
249
250
  
  	/*
  	 * Mark it as orphaned to destroy the segment when
  	 * kernel.shm_rmid_forced is changed.
  	 * It is noop if the following shm_may_destroy() returns true.
  	 */
  	shp->shm_creator = NULL;
  
  	/*
  	 * Don't even try to destroy it.  If shm_rmid_forced=0 and IPC_RMID
  	 * is not set, it shouldn't be deleted here.
  	 */
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
251
  	if (!ns->shm_rmid_forced)
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
252
  		return 0;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
253

4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
254
255
  	if (shm_may_destroy(ns, shp)) {
  		shm_lock_by_ptr(shp);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
256
  		shm_destroy(ns, shp);
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
257
  	}
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
258
259
  	return 0;
  }
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
260
  /* Called with ns->shm_ids(ns).rw_mutex locked */
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
261
262
263
  static int shm_try_destroy_orphaned(int id, void *p, void *data)
  {
  	struct ipc_namespace *ns = data;
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
264
265
  	struct kern_ipc_perm *ipcp = p;
  	struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
266
267
268
269
  
  	/*
  	 * We want to destroy segments without users and with already
  	 * exit'ed originating process.
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
270
271
  	 *
  	 * As shp->* are changed under rw_mutex, it's safe to skip shp locking.
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
272
  	 */
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
273
  	if (shp->shm_creator != NULL)
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
274
  		return 0;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
275

4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
276
277
  	if (shm_may_destroy(ns, shp)) {
  		shm_lock_by_ptr(shp);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
278
  		shm_destroy(ns, shp);
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
279
  	}
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
280
281
282
283
284
285
  	return 0;
  }
  
  void shm_destroy_orphaned(struct ipc_namespace *ns)
  {
  	down_write(&shm_ids(ns).rw_mutex);
33a30ed4b   Vasiliy Kulikov   shm: fix wrong tests
286
  	if (shm_ids(ns).in_use)
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
287
  		idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
288
289
290
291
292
293
  	up_write(&shm_ids(ns).rw_mutex);
  }
  
  
  void exit_shm(struct task_struct *task)
  {
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
294
  	struct ipc_namespace *ns = task->nsproxy->ipc_ns;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
295

298507d4d   Vasiliy Kulikov   shm: optimize exi...
296
297
  	if (shm_ids(ns).in_use == 0)
  		return;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
298
299
  	/* Destroy all already created segments, but not mapped yet */
  	down_write(&shm_ids(ns).rw_mutex);
33a30ed4b   Vasiliy Kulikov   shm: fix wrong tests
300
  	if (shm_ids(ns).in_use)
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
301
  		idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns);
3e148c799   Nadia Derbey   fix idr_find() lo...
302
  	up_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  }
d0217ac04   Nick Piggin   mm: fault feedbac...
304
  static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
305
306
307
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
d0217ac04   Nick Piggin   mm: fault feedbac...
308
  	return sfd->vm_ops->fault(vma, vmf);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
309
310
311
  }
  
  #ifdef CONFIG_NUMA
d823e3e75   Adrian Bunk   ipc/shm.c: make 2...
312
  static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
313
314
315
316
317
318
319
320
  {
  	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...
321
322
  static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
  					unsigned long addr)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
323
324
325
326
327
328
329
  {
  	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...
330
  	else if (vma->vm_policy)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
331
  		pol = vma->vm_policy;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
332

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
333
334
335
  	return pol;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
  static int shm_mmap(struct file * file, struct vm_area_struct * vma)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
338
  	struct shm_file_data *sfd = shm_file_data(file);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
339
  	int ret;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
340
341
342
343
  	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...
344
  #ifdef CONFIG_MMU
54cb8821d   Nick Piggin   mm: merge populat...
345
  	BUG_ON(!sfd->vm_ops->fault);
2e92a3bae   David Howells   NOMMU: Fix SYSV I...
346
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
347
348
  	vma->vm_ops = &shm_vm_ops;
  	shm_open(vma);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
349
350
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
352
353
  static int shm_release(struct inode *ino, struct file *file)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
354
  	struct shm_file_data *sfd = shm_file_data(file);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
355

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
356
357
358
  	put_ipc_ns(sfd->ns);
  	shm_file_data(file) = NULL;
  	kfree(sfd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
359
360
  	return 0;
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
361
  static int shm_fsync(struct file *file, loff_t start, loff_t end, int datasync)
516dffdcd   Adam Litke   [PATCH] Fix get_u...
362
  {
516dffdcd   Adam Litke   [PATCH] Fix get_u...
363
  	struct shm_file_data *sfd = shm_file_data(file);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
364

7ea808591   Christoph Hellwig   drop unused dentr...
365
366
  	if (!sfd->file->f_op->fsync)
  		return -EINVAL;
02c24a821   Josef Bacik   fs: push i_mutex ...
367
  	return sfd->file->f_op->fsync(sfd->file, start, end, datasync);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
368
  }
7d8a45695   Will Deacon   ipc: shm: restore...
369
370
371
372
373
374
375
376
377
  static long shm_fallocate(struct file *file, int mode, loff_t offset,
  			  loff_t len)
  {
  	struct shm_file_data *sfd = shm_file_data(file);
  
  	if (!sfd->file->f_op->fallocate)
  		return -EOPNOTSUPP;
  	return sfd->file->f_op->fallocate(file, mode, offset, len);
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
378
379
380
381
382
  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);
c4caa7781   Al Viro   file ->get_unmapp...
383
384
  	return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len,
  						pgoff, flags);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
385
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
386

9a32144e9   Arjan van de Ven   [PATCH] mark stru...
387
  static const struct file_operations shm_file_operations = {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
388
  	.mmap		= shm_mmap,
516dffdcd   Adam Litke   [PATCH] Fix get_u...
389
  	.fsync		= shm_fsync,
4e9823111   Kirill Korotaev   [PATCH] IPC names...
390
  	.release	= shm_release,
ed5e5894b   David Howells   nommu: fix SYSV S...
391
392
393
  #ifndef CONFIG_MMU
  	.get_unmapped_area	= shm_get_unmapped_area,
  #endif
6038f373a   Arnd Bergmann   llseek: automatic...
394
  	.llseek		= noop_llseek,
7d8a45695   Will Deacon   ipc: shm: restore...
395
  	.fallocate	= shm_fallocate,
c4caa7781   Al Viro   file ->get_unmapp...
396
397
398
399
400
401
  };
  
  static const struct file_operations shm_file_operations_huge = {
  	.mmap		= shm_mmap,
  	.fsync		= shm_fsync,
  	.release	= shm_release,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
402
  	.get_unmapped_area	= shm_get_unmapped_area,
6038f373a   Arnd Bergmann   llseek: automatic...
403
  	.llseek		= noop_llseek,
7d8a45695   Will Deacon   ipc: shm: restore...
404
  	.fallocate	= shm_fallocate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
  };
c4caa7781   Al Viro   file ->get_unmapp...
406
407
408
409
  int is_file_shm_hugepages(struct file *file)
  {
  	return file->f_op == &shm_file_operations_huge;
  }
f0f37e2f7   Alexey Dobriyan   const: mark struc...
410
  static const struct vm_operations_struct shm_vm_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
  	.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...
413
  	.fault	= shm_fault,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
414
415
416
  #if defined(CONFIG_NUMA)
  	.set_policy = shm_set_policy,
  	.get_policy = shm_get_policy,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
  #endif
  };
f4566f048   Nadia Derbey   ipc: fix wrong co...
419
420
421
422
423
  /**
   * 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...
424
   * Called with shm_ids.rw_mutex held as a writer.
f4566f048   Nadia Derbey   ipc: fix wrong co...
425
   */
7748dbfaa   Nadia Derbey   ipc: unify the sy...
426
  static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
  {
7748dbfaa   Nadia Derbey   ipc: unify the sy...
428
429
430
  	key_t key = params->key;
  	int shmflg = params->flg;
  	size_t size = params->u.size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
  	int error;
  	struct shmid_kernel *shp;
d69f3bad4   Robin Holt   ipc: sysv shared ...
433
  	size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
  	struct file * file;
  	char name[13];
  	int id;
ca16d140a   KOSAKI Motohiro   mm: don't access ...
437
  	vm_flags_t acctflag = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438

4e9823111   Kirill Korotaev   [PATCH] IPC names...
439
  	if (size < SHMMIN || size > ns->shm_ctlmax)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  		return -EINVAL;
f66d45e99   Guy Streeter   [PATCH] correct s...
441
  	if (ns->shm_tot + numpages > ns->shm_ctlall)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
447
448
  		return -ENOSPC;
  
  	shp = ipc_rcu_alloc(sizeof(*shp));
  	if (!shp)
  		return -ENOMEM;
  
  	shp->shm_perm.key = key;
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
449
  	shp->shm_perm.mode = (shmflg & S_IRWXUGO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
452
453
454
455
456
457
  	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...
458
  	sprintf (name, "SYSV%08x", key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  	if (shmflg & SHM_HUGETLB) {
c103a4dc4   Andrew Morton   ipc/shmc.c: elimi...
460
  		struct hstate *hs;
091d0d55b   Li Zefan   shm: fix null poi...
461
  		size_t hugesize;
c103a4dc4   Andrew Morton   ipc/shmc.c: elimi...
462
  		hs = hstate_sizelog((shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
091d0d55b   Li Zefan   shm: fix null poi...
463
464
465
466
467
  		if (!hs) {
  			error = -EINVAL;
  			goto no_file;
  		}
  		hugesize = ALIGN(size, huge_page_size(hs));
af73e4d95   Naoya Horiguchi   hugetlbfs: fix mm...
468

5a6fe1259   Mel Gorman   Do not account fo...
469
470
471
  		/* hugetlb_file_setup applies strict accounting */
  		if (shmflg & SHM_NORESERVE)
  			acctflag = VM_NORESERVE;
af73e4d95   Naoya Horiguchi   hugetlbfs: fix mm...
472
  		file = hugetlb_file_setup(name, hugesize, acctflag,
42d7395fe   Andi Kleen   mm: support more ...
473
474
  				  &shp->mlock_user, HUGETLB_SHMFS_INODE,
  				(shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
  	} else {
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
476
477
478
479
480
481
  		/*
  		 * Do not allow no accounting for OVERCOMMIT_NEVER, even
  	 	 * if it's asked for.
  		 */
  		if  ((shmflg & SHM_NORESERVE) &&
  				sysctl_overcommit_memory != OVERCOMMIT_NEVER)
fc8744adc   Linus Torvalds   Stop playing sill...
482
  			acctflag = VM_NORESERVE;
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
483
  		file = shmem_file_setup(name, size, acctflag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
485
486
487
  	}
  	error = PTR_ERR(file);
  	if (IS_ERR(file))
  		goto no_file;
48dea404e   Pierre Peiffer   IPC: use ipc_buil...
488
  	id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
283bb7fad   Pierre Peiffer   IPC: fix error ca...
489
490
  	if (id < 0) {
  		error = id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
491
  		goto no_id;
283bb7fad   Pierre Peiffer   IPC: fix error ca...
492
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493

b488893a3   Pavel Emelyanov   pid namespaces: c...
494
  	shp->shm_cprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
498
499
  	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
500
  	shp->shm_file = file;
5774ed014   Vasiliy Kulikov   shm: handle separ...
501
  	shp->shm_creator = current;
dbfcd91f0   Davidlohr Bueso   ipc: move rcu loc...
502

30475cc12   Badari Pulavarty   Restore shmid as ...
503
504
505
506
  	/*
  	 * shmid gets reported as "inode#" in /proc/pid/maps.
  	 * proc-ps tools use this. Changing this will break them.
  	 */
496ad9aa8   Al Viro   new helper: file_...
507
  	file_inode(file)->i_ino = shp->shm_perm.id;
551110a94   Krishnakumar R   [PATCH] hugetlb: ...
508

4e9823111   Kirill Korotaev   [PATCH] IPC names...
509
  	ns->shm_tot += numpages;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
510
  	error = shp->shm_perm.id;
dbfcd91f0   Davidlohr Bueso   ipc: move rcu loc...
511

cf9d5d78d   Davidlohr Bueso   ipc: close open c...
512
  	ipc_unlock_object(&shp->shm_perm);
dbfcd91f0   Davidlohr Bueso   ipc: move rcu loc...
513
  	rcu_read_unlock();
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
514
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
  
  no_id:
2195d2818   Hugh Dickins   fix undefined ref...
517
  	if (is_file_hugepages(file) && shp->mlock_user)
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
518
  		user_shm_unlock(size, shp->mlock_user);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
520
521
522
523
524
  	fput(file);
  no_file:
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  	return error;
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
525
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
526
   * Called with shm_ids.rw_mutex and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
527
   */
03f02c765   Nadia Derbey   Storing ipcs into...
528
  static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
529
  {
03f02c765   Nadia Derbey   Storing ipcs into...
530
531
532
533
  	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...
534
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
535
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
536
   * Called with shm_ids.rw_mutex and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
537
   */
03f02c765   Nadia Derbey   Storing ipcs into...
538
539
  static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
  				struct ipc_params *params)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
540
  {
03f02c765   Nadia Derbey   Storing ipcs into...
541
542
543
544
  	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...
545
546
547
548
  		return -EINVAL;
  
  	return 0;
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
549
  SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
551
  	struct ipc_namespace *ns;
7748dbfaa   Nadia Derbey   ipc: unify the sy...
552
553
  	struct ipc_ops shm_ops;
  	struct ipc_params shm_params;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
554
555
  
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556

7748dbfaa   Nadia Derbey   ipc: unify the sy...
557
558
559
  	shm_ops.getnew = newseg;
  	shm_ops.associate = shm_security;
  	shm_ops.more_checks = shm_more_checks;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
560

7748dbfaa   Nadia Derbey   ipc: unify the sy...
561
562
563
  	shm_params.key = key;
  	shm_params.flg = shmflg;
  	shm_params.u.size = size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564

7748dbfaa   Nadia Derbey   ipc: unify the sy...
565
  	return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
567
568
569
570
571
572
573
574
575
  }
  
  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;
3af54c9bd   Vasiliy Kulikov   ipc: shm: fix inf...
576
  		memset(&out, 0, sizeof(out));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
  		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...
592
593
  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
594
595
596
  {
  	switch(version) {
  	case IPC_64:
016d7132f   Pierre Peiffer   IPC: get rid of t...
597
  		if (copy_from_user(out, buf, sizeof(*out)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
602
603
604
605
  	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...
606
607
608
  		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
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
  
  		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...
642
  /*
b79521807   Helge Deller   ipc/shm.c: add RS...
643
644
645
646
647
648
649
   * Calculate and add used RSS and swap pages of a shm.
   * Called with shm_ids.rw_mutex held as a reader
   */
  static void shm_add_rss_swap(struct shmid_kernel *shp,
  	unsigned long *rss_add, unsigned long *swp_add)
  {
  	struct inode *inode;
496ad9aa8   Al Viro   new helper: file_...
650
  	inode = file_inode(shp->shm_file);
b79521807   Helge Deller   ipc/shm.c: add RS...
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
  
  	if (is_file_hugepages(shp->shm_file)) {
  		struct address_space *mapping = inode->i_mapping;
  		struct hstate *h = hstate_file(shp->shm_file);
  		*rss_add += pages_per_huge_page(h) * mapping->nrpages;
  	} else {
  #ifdef CONFIG_SHMEM
  		struct shmem_inode_info *info = SHMEM_I(inode);
  		spin_lock(&info->lock);
  		*rss_add += inode->i_mapping->nrpages;
  		*swp_add += info->swapped;
  		spin_unlock(&info->lock);
  #else
  		*rss_add += inode->i_mapping->nrpages;
  #endif
  	}
  }
  
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
670
   * Called with shm_ids.rw_mutex held as a reader
f4566f048   Nadia Derbey   ipc: fix wrong co...
671
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
672
673
  static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
  		unsigned long *swp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
675
676
  	int next_id;
  	int total, in_use;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
678
679
  
  	*rss = 0;
  	*swp = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
680
681
682
  	in_use = shm_ids(ns).in_use;
  
  	for (total = 0, next_id = 0; total < in_use; next_id++) {
e562aebc6   Tony Battersby   ipc: make shm_get...
683
  		struct kern_ipc_perm *ipc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
  		struct shmid_kernel *shp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685

e562aebc6   Tony Battersby   ipc: make shm_get...
686
687
  		ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
  		if (ipc == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
  			continue;
e562aebc6   Tony Battersby   ipc: make shm_get...
689
  		shp = container_of(ipc, struct shmid_kernel, shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
690

b79521807   Helge Deller   ipc/shm.c: add RS...
691
  		shm_add_rss_swap(shp, rss, swp);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
692
693
  
  		total++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
  	}
  }
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
696
697
698
699
700
701
702
  /*
   * 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
703
  {
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
704
  	struct kern_ipc_perm *ipcp;
016d7132f   Pierre Peiffer   IPC: get rid of t...
705
  	struct shmid64_ds shmid64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
  	struct shmid_kernel *shp;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
707
708
709
  	int err;
  
  	if (cmd == IPC_SET) {
016d7132f   Pierre Peiffer   IPC: get rid of t...
710
  		if (copy_shmid_from_user(&shmid64, buf, version))
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
711
712
  			return -EFAULT;
  	}
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
713
714
  	down_write(&shm_ids(ns).rw_mutex);
  	rcu_read_lock();
b0e77598f   Serge E. Hallyn   userns: user name...
715
716
  	ipcp = ipcctl_pre_down(ns, &shm_ids(ns), shmid, cmd,
  			       &shmid64.shm_perm, 0);
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
717
718
719
720
721
  	if (IS_ERR(ipcp)) {
  		err = PTR_ERR(ipcp);
  		/* the ipc lock is not held upon failure */
  		goto out_unlock1;
  	}
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
722

a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
723
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
724
725
726
  
  	err = security_shm_shmctl(shp, cmd);
  	if (err)
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
727
  		goto out_unlock0;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
728
729
  	switch (cmd) {
  	case IPC_RMID:
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
730
  		/* do_shm_rmid unlocks the ipc object and rcu */
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
731
732
733
  		do_shm_rmid(ns, ipcp);
  		goto out_up;
  	case IPC_SET:
1efdb69b0   Eric W. Biederman   userns: Convert i...
734
735
  		err = ipc_update_perm(&shmid64.shm_perm, ipcp);
  		if (err)
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
736
  			goto out_unlock0;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
737
738
739
740
741
  		shp->shm_ctim = get_seconds();
  		break;
  	default:
  		err = -EINVAL;
  	}
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
742
743
744
745
746
  
  out_unlock0:
  	ipc_unlock_object(&shp->shm_perm);
  out_unlock1:
  	rcu_read_unlock();
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
747
748
749
750
  out_up:
  	up_write(&shm_ids(ns).rw_mutex);
  	return err;
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
751
  SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
752
753
  {
  	struct shmid_kernel *shp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
  	int err, version;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
755
  	struct ipc_namespace *ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
757
758
759
760
761
762
  
  	if (cmd < 0 || shmid < 0) {
  		err = -EINVAL;
  		goto out;
  	}
  
  	version = ipc_parse_version(&cmd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
763
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
766
767
768
769
770
771
772
  
  	switch (cmd) { /* replace with proc interface ? */
  	case IPC_INFO:
  	{
  		struct shminfo64 shminfo;
  
  		err = security_shm_shmctl(NULL, cmd);
  		if (err)
  			return err;
e8148f758   WANG Cong   ipc: clean up ipc...
773
  		memset(&shminfo, 0, sizeof(shminfo));
4e9823111   Kirill Korotaev   [PATCH] IPC names...
774
775
776
  		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
777
778
779
780
  
  		shminfo.shmmin = SHMMIN;
  		if(copy_shminfo_to_user (buf, &shminfo, version))
  			return -EFAULT;
f4566f048   Nadia Derbey   ipc: fix wrong co...
781

3e148c799   Nadia Derbey   fix idr_find() lo...
782
  		down_read(&shm_ids(ns).rw_mutex);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
783
  		err = ipc_get_maxid(&shm_ids(ns));
3e148c799   Nadia Derbey   fix idr_find() lo...
784
  		up_read(&shm_ids(ns).rw_mutex);
f4566f048   Nadia Derbey   ipc: fix wrong co...
785

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
791
792
793
794
795
796
  		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;
e8148f758   WANG Cong   ipc: clean up ipc...
797
  		memset(&shm_info, 0, sizeof(shm_info));
3e148c799   Nadia Derbey   fix idr_find() lo...
798
  		down_read(&shm_ids(ns).rw_mutex);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
799
800
801
  		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
802
803
  		shm_info.swap_attempts = 0;
  		shm_info.swap_successes = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
804
  		err = ipc_get_maxid(&shm_ids(ns));
3e148c799   Nadia Derbey   fix idr_find() lo...
805
  		up_read(&shm_ids(ns).rw_mutex);
e8148f758   WANG Cong   ipc: clean up ipc...
806
  		if (copy_to_user(buf, &shm_info, sizeof(shm_info))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
809
810
811
812
813
814
815
816
817
818
  			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...
819

023a53557   Nadia Derbey   ipc: integrate ip...
820
821
822
823
824
825
  		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...
826
  			result = shp->shm_perm.id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  		} else {
023a53557   Nadia Derbey   ipc: integrate ip...
828
829
830
831
832
  			shp = shm_lock_check(ns, shmid);
  			if (IS_ERR(shp)) {
  				err = PTR_ERR(shp);
  				goto out;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
833
834
  			result = 0;
  		}
e8148f758   WANG Cong   ipc: clean up ipc...
835
  		err = -EACCES;
b0e77598f   Serge E. Hallyn   userns: user name...
836
  		if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
840
  			goto out_unlock;
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock;
023a53557   Nadia Derbey   ipc: integrate ip...
841
  		memset(&tbuf, 0, sizeof(tbuf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
843
844
845
846
847
848
  		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...
849
  		tbuf.shm_nattch	= shp->shm_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
850
851
852
853
854
855
856
857
858
859
  		shm_unlock(shp);
  		if(copy_shmid_to_user (buf, &tbuf, version))
  			err = -EFAULT;
  		else
  			err = result;
  		goto out;
  	}
  	case SHM_LOCK:
  	case SHM_UNLOCK:
  	{
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
860
  		struct file *shm_file;
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
861

023a53557   Nadia Derbey   ipc: integrate ip...
862
863
864
  		shp = shm_lock_check(ns, shmid);
  		if (IS_ERR(shp)) {
  			err = PTR_ERR(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865
866
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867

a33e67510   Al Viro   sanitize audit_ip...
868
  		audit_ipc_obj(&(shp->shm_perm));
073115d6b   Steve Grubb   [PATCH] Rework of...
869

b0e77598f   Serge E. Hallyn   userns: user name...
870
  		if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
1efdb69b0   Eric W. Biederman   userns: Convert i...
871
  			kuid_t euid = current_euid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
  			err = -EPERM;
1efdb69b0   Eric W. Biederman   userns: Convert i...
873
874
  			if (!uid_eq(euid, shp->shm_perm.uid) &&
  			    !uid_eq(euid, shp->shm_perm.cuid))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
  				goto out_unlock;
f1eb1332b   Jiri Slaby   ipc: use rlimit h...
876
  			if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
877
878
879
880
881
882
  				goto out_unlock;
  		}
  
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock;
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
883
884
885
886
887
888
  
  		shm_file = shp->shm_file;
  		if (is_file_hugepages(shm_file))
  			goto out_unlock;
  
  		if (cmd == SHM_LOCK) {
86a264abe   David Howells   CRED: Wrap curren...
889
  			struct user_struct *user = current_user();
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
890
891
892
893
  			err = shmem_lock(shm_file, 1, user);
  			if (!err && !(shp->shm_perm.mode & SHM_LOCKED)) {
  				shp->shm_perm.mode |= SHM_LOCKED;
  				shp->mlock_user = user;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
  			}
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
895
  			goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
896
  		}
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
897
898
899
900
901
902
903
904
  
  		/* SHM_UNLOCK */
  		if (!(shp->shm_perm.mode & SHM_LOCKED))
  			goto out_unlock;
  		shmem_lock(shm_file, 0, shp->mlock_user);
  		shp->shm_perm.mode &= ~SHM_LOCKED;
  		shp->mlock_user = NULL;
  		get_file(shm_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
  		shm_unlock(shp);
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
906
  		shmem_unlock_mapping(shm_file->f_mapping);
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
907
  		fput(shm_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
908
909
910
  		goto out;
  	}
  	case IPC_RMID:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
  	case IPC_SET:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
912
913
  		err = shmctl_down(ns, shmid, cmd, buf, version);
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
  	default:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
915
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917
918
919
920
921
922
923
924
925
926
927
928
929
  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.
   */
079a96ae3   Will Deacon   ipc: add COMPAT_S...
930
931
  long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
  	      unsigned long shmlba)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
935
936
937
938
939
  {
  	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
940
  	int acc_mode;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
941
  	struct ipc_namespace *ns;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
942
943
  	struct shm_file_data *sfd;
  	struct path path;
aeb5d7270   Al Viro   [PATCH] introduce...
944
  	fmode_t f_mode;
41badc15c   Michel Lespinasse   mm: make do_mmap_...
945
  	unsigned long populate = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
947
948
  	err = -EINVAL;
  	if (shmid < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
  		goto out;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
950
  	else if ((addr = (ulong)shmaddr)) {
079a96ae3   Will Deacon   ipc: add COMPAT_S...
951
  		if (addr & (shmlba - 1)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
952
  			if (shmflg & SHM_RND)
079a96ae3   Will Deacon   ipc: add COMPAT_S...
953
  				addr &= ~(shmlba - 1);	   /* round down */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
954
955
956
957
  			else
  #ifndef __ARCH_FORCE_SHMLBA
  				if (addr & ~PAGE_MASK)
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
958
  					goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
959
960
961
962
  		}
  		flags = MAP_SHARED | MAP_FIXED;
  	} else {
  		if ((shmflg & SHM_REMAP))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
963
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
964
965
966
967
968
969
  
  		flags = MAP_SHARED;
  	}
  
  	if (shmflg & SHM_RDONLY) {
  		prot = PROT_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
970
  		acc_mode = S_IRUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
971
  		f_mode = FMODE_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
  	} else {
  		prot = PROT_READ | PROT_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
974
  		acc_mode = S_IRUGO | S_IWUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
975
  		f_mode = FMODE_READ | FMODE_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
976
977
978
979
980
981
982
983
984
985
  	}
  	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...
986
  	ns = current->nsproxy->ipc_ns;
023a53557   Nadia Derbey   ipc: integrate ip...
987
988
989
  	shp = shm_lock_check(ns, shmid);
  	if (IS_ERR(shp)) {
  		err = PTR_ERR(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
  		goto out;
023a53557   Nadia Derbey   ipc: integrate ip...
991
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
992
993
  
  	err = -EACCES;
b0e77598f   Serge E. Hallyn   userns: user name...
994
  	if (ipcperms(ns, &shp->shm_perm, acc_mode))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
995
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
996
997
  
  	err = security_shm_shmat(shp, shmaddr, shmflg);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
998
999
  	if (err)
  		goto out_unlock;
2c48b9c45   Al Viro   switch alloc_file...
1000
1001
  	path = shp->shm_file->f_path;
  	path_get(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
  	shp->shm_nattch++;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1003
  	size = i_size_read(path.dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
  	shm_unlock(shp);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1005
1006
1007
  	err = -ENOMEM;
  	sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
  	if (!sfd)
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
1008
  		goto out_put_dentry;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1009

2c48b9c45   Al Viro   switch alloc_file...
1010
1011
  	file = alloc_file(&path, f_mode,
  			  is_file_hugepages(shp->shm_file) ?
c4caa7781   Al Viro   file ->get_unmapp...
1012
1013
  				&shm_file_operations_huge :
  				&shm_file_operations);
39b652527   Anatol Pomozov   fs: Preserve erro...
1014
1015
  	err = PTR_ERR(file);
  	if (IS_ERR(file))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1016
  		goto out_free;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1017
  	file->private_data = sfd;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1018
  	file->f_mapping = shp->shm_file->f_mapping;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
1019
  	sfd->id = shp->shm_perm.id;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1020
1021
1022
  	sfd->ns = get_ipc_ns(ns);
  	sfd->file = shp->shm_file;
  	sfd->vm_ops = NULL;
8b3ec6814   Al Viro   take security_mma...
1023
1024
1025
  	err = security_mmap_file(file, prot, flags);
  	if (err)
  		goto out_fput;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026
1027
  	down_write(&current->mm->mmap_sem);
  	if (addr && !(shmflg & SHM_REMAP)) {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1028
  		err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
  		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;
  	}
  		
bebeb3d68   Michel Lespinasse   mm: introduce mm_...
1040
1041
  	addr = do_mmap_pgoff(file, addr, size, prot, flags, 0, &populate);
  	*raddr = addr;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1042
  	err = 0;
bebeb3d68   Michel Lespinasse   mm: introduce mm_...
1043
1044
  	if (IS_ERR_VALUE(addr))
  		err = (long)addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
1046
  invalid:
  	up_write(&current->mm->mmap_sem);
bebeb3d68   Michel Lespinasse   mm: introduce mm_...
1047
  	if (populate)
41badc15c   Michel Lespinasse   mm: make do_mmap_...
1048
  		mm_populate(addr, populate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1049

8b3ec6814   Al Viro   take security_mma...
1050
  out_fput:
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1051
1052
1053
  	fput(file);
  
  out_nattch:
3e148c799   Nadia Derbey   fix idr_find() lo...
1054
  	down_write(&shm_ids(ns).rw_mutex);
00c2bf85d   Nadia Derbey   ipc: get rid of i...
1055
  	shp = shm_lock(ns, shmid);
023a53557   Nadia Derbey   ipc: integrate ip...
1056
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1057
  	shp->shm_nattch--;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
1058
  	if (shm_may_destroy(ns, shp))
4e9823111   Kirill Korotaev   [PATCH] IPC names...
1059
  		shm_destroy(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
  	else
  		shm_unlock(shp);
3e148c799   Nadia Derbey   fix idr_find() lo...
1062
  	up_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1064
1065
  out:
  	return err;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1066
1067
1068
1069
1070
1071
1072
  
  out_unlock:
  	shm_unlock(shp);
  	goto out;
  
  out_free:
  	kfree(sfd);
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
1073
  out_put_dentry:
2c48b9c45   Al Viro   switch alloc_file...
1074
  	path_put(&path);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1075
  	goto out_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1076
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
1077
  SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
1078
1079
1080
  {
  	unsigned long ret;
  	long err;
079a96ae3   Will Deacon   ipc: add COMPAT_S...
1081
  	err = do_shmat(shmid, shmaddr, shmflg, &ret, SHMLBA);
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
1082
1083
1084
1085
1086
  	if (err)
  		return err;
  	force_successful_syscall_return();
  	return (long)ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
1088
1089
1090
  /*
   * detach and kill segment if marked destroyed.
   * The work is done in shm_close.
   */
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
1091
  SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
1093
  {
  	struct mm_struct *mm = current->mm;
586c7e6a2   Mike Frysinger   shm: fix unused w...
1094
  	struct vm_area_struct *vma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1095
  	unsigned long addr = (unsigned long)shmaddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
  	int retval = -EINVAL;
586c7e6a2   Mike Frysinger   shm: fix unused w...
1097
1098
1099
1100
  #ifdef CONFIG_MMU
  	loff_t size = 0;
  	struct vm_area_struct *next;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101

df1e2fb54   Hugh Dickins   [PATCH] shmdt: ch...
1102
1103
  	if (addr & ~PAGE_MASK)
  		return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
  	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);
8feae1311   David Howells   NOMMU: Make VMAs ...
1127
  #ifdef CONFIG_MMU
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1128
1129
1130
1131
1132
1133
1134
1135
  	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...
1136
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1137
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
496ad9aa8   Al Viro   new helper: file_...
1138
  			size = file_inode(vma->vm_file)->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
  			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
25985edce   Lucas De Marchi   Fix common misspe...
1156
  	 * prevent overflows and make comparisons vs. equal-width types.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1157
  	 */
8e36709d8   KAMEZAWA Hiroyuki   [PATCH] shmdt can...
1158
  	size = PAGE_ALIGN(size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1159
1160
1161
1162
  	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...
1163
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1164
1165
1166
1167
1168
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
  
  			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
  		vma = next;
  	}
8feae1311   David Howells   NOMMU: Make VMAs ...
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
  #else /* CONFIG_MMU */
  	/* under NOMMU conditions, the exact address to be destroyed must be
  	 * given */
  	retval = -EINVAL;
  	if (vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) {
  		do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
  		retval = 0;
  	}
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1179
1180
1181
1182
1183
  	up_write(&mm->mmap_sem);
  	return retval;
  }
  
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1184
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1185
  {
1efdb69b0   Eric W. Biederman   userns: Convert i...
1186
  	struct user_namespace *user_ns = seq_user_ns(s);
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1187
  	struct shmid_kernel *shp = it;
b79521807   Helge Deller   ipc/shm.c: add RS...
1188
1189
1190
  	unsigned long rss = 0, swp = 0;
  
  	shm_add_rss_swap(shp, &rss, &swp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1191

6c826818f   Paul Menage   /proc/sysvipc/shm...
1192
1193
1194
1195
1196
  #if BITS_PER_LONG <= 32
  #define SIZE_SPEC "%10lu"
  #else
  #define SIZE_SPEC "%21lu"
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1197

6c826818f   Paul Menage   /proc/sysvipc/shm...
1198
1199
  	return seq_printf(s,
  			  "%10d %10d  %4o " SIZE_SPEC " %5u %5u  "
b79521807   Helge Deller   ipc/shm.c: add RS...
1200
1201
1202
  			  "%5lu %5u %5u %5u %5u %10lu %10lu %10lu "
  			  SIZE_SPEC " " SIZE_SPEC "
  ",
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1203
  			  shp->shm_perm.key,
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
1204
  			  shp->shm_perm.id,
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
1205
  			  shp->shm_perm.mode,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1206
1207
1208
  			  shp->shm_segsz,
  			  shp->shm_cprid,
  			  shp->shm_lprid,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1209
  			  shp->shm_nattch,
1efdb69b0   Eric W. Biederman   userns: Convert i...
1210
1211
1212
1213
  			  from_kuid_munged(user_ns, shp->shm_perm.uid),
  			  from_kgid_munged(user_ns, shp->shm_perm.gid),
  			  from_kuid_munged(user_ns, shp->shm_perm.cuid),
  			  from_kgid_munged(user_ns, shp->shm_perm.cgid),
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1214
1215
  			  shp->shm_atim,
  			  shp->shm_dtim,
b79521807   Helge Deller   ipc/shm.c: add RS...
1216
1217
1218
  			  shp->shm_ctim,
  			  rss * PAGE_SIZE,
  			  swp * PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219
1220
  }
  #endif