Blame view

ipc/shm.c 31.5 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>
bd58e2dc2   Davidlohr Bueso   ipc,shm: shorten ...
22
23
24
   *
   * Better ipc lock (kern_ipc_perm.lock) handling
   * Davidlohr Bueso <davidlohr.bueso@hp.com>, June 2013.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
30
31
32
  #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
33
34
35
36
  #include <linux/shmem_fs.h>
  #include <linux/security.h>
  #include <linux/syscalls.h>
  #include <linux/audit.h>
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
37
  #include <linux/capability.h>
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
38
  #include <linux/ptrace.h>
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
39
  #include <linux/seq_file.h>
3e148c799   Nadia Derbey   fix idr_find() lo...
40
  #include <linux/rwsem.h>
4e9823111   Kirill Korotaev   [PATCH] IPC names...
41
  #include <linux/nsproxy.h>
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
42
  #include <linux/mount.h>
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
43
  #include <linux/ipc_namespace.h>
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
44

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
  #include <asm/uaccess.h>
  
  #include "util.h"
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
48
49
50
51
52
53
54
55
  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...
56
  static const struct file_operations shm_file_operations;
f0f37e2f7   Alexey Dobriyan   const: mark struc...
57
  static const struct vm_operations_struct shm_vm_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58

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

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

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

140d0b210   Linus Torvalds   Do 'shm_init_ns()...
104
  static int __init ipc_ns_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
105
  {
ed2ddbf88   Pierre Peiffer   IPC: make struct ...
106
  	shm_init_ns(&init_ipc_ns);
140d0b210   Linus Torvalds   Do 'shm_init_ns()...
107
108
109
110
111
112
113
  	return 0;
  }
  
  pure_initcall(ipc_ns_init);
  
  void __init shm_init (void)
  {
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
114
  	ipc_init_proc_interface("sysvipc/shm",
b79521807   Helge Deller   ipc/shm.c: add RS...
115
116
117
118
119
120
121
  #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...
122
  				IPC_SHM_IDS, sysvipc_shm_proc_show);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
  }
1b2ad1674   Davidlohr Bueso   ipc,shm: introduc...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  static inline struct shmid_kernel *shm_obtain_object(struct ipc_namespace *ns, int id)
  {
  	struct kern_ipc_perm *ipcp = ipc_obtain_object(&shm_ids(ns), id);
  
  	if (IS_ERR(ipcp))
  		return ERR_CAST(ipcp);
  
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
  }
  
  static inline struct shmid_kernel *shm_obtain_object_check(struct ipc_namespace *ns, int id)
  {
  	struct kern_ipc_perm *ipcp = ipc_obtain_object_check(&shm_ids(ns), id);
  
  	if (IS_ERR(ipcp))
  		return ERR_CAST(ipcp);
  
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
  }
3e148c799   Nadia Derbey   fix idr_find() lo...
143
  /*
33b746698   Davidlohr Bueso   ipc: rename ids->...
144
   * shm_lock_(check_) routines are called in the paths where the rwsem
00c2bf85d   Nadia Derbey   ipc: get rid of i...
145
   * is not necessarily held.
3e148c799   Nadia Derbey   fix idr_find() lo...
146
   */
023a53557   Nadia Derbey   ipc: integrate ip...
147
  static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  {
03f02c765   Nadia Derbey   Storing ipcs into...
149
  	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
b1ed88b47   Pierre Peiffer   IPC: fix error ch...
150
151
  	if (IS_ERR(ipcp))
  		return (struct shmid_kernel *)ipcp;
03f02c765   Nadia Derbey   Storing ipcs into...
152
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
023a53557   Nadia Derbey   ipc: integrate ip...
153
  }
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
154
155
156
  static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
  {
  	rcu_read_lock();
115d40dbe   Davidlohr Bueso   ipc: close open c...
157
  	ipc_lock_object(&ipcp->shm_perm);
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
158
  }
e84ca3337   Davidlohr Bueso   ipc: fix race wit...
159
160
161
162
163
164
165
166
  static void shm_rcu_free(struct rcu_head *head)
  {
  	struct ipc_rcu *p = container_of(head, struct ipc_rcu, rcu);
  	struct shmid_kernel *shp = ipc_rcu_to_struct(p);
  
  	security_shm_free(shp);
  	ipc_rcu_free(head);
  }
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
167
  static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
169
  	ipc_rmid(&shm_ids(ns), &s->shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
172
173
  /* 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...
174
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
175
176
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
178
  	shp = shm_lock(sfd->ns, sfd->id);
023a53557   Nadia Derbey   ipc: integrate ip...
179
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  	shp->shm_atim = get_seconds();
b488893a3   Pavel Emelyanov   pid namespaces: c...
181
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
  	shp->shm_nattch++;
  	shm_unlock(shp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
  /*
   * shm_destroy - free the struct shmid_kernel
   *
f4566f048   Nadia Derbey   ipc: fix wrong co...
188
   * @ns: namespace
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
   * @shp: struct to free
   *
33b746698   Davidlohr Bueso   ipc: rename ids->...
191
   * It has to be called with shp and shm_ids.rwsem (writer) locked,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
193
   * but returns with shp unlocked and freed.
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
194
  static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
196
  	ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
197
  	shm_rmid(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
199
200
  	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...
201
  	else if (shp->mlock_user)
496ad9aa8   Al Viro   new helper: file_...
202
  		user_shm_unlock(file_inode(shp->shm_file)->i_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
203
204
  						shp->mlock_user);
  	fput (shp->shm_file);
e84ca3337   Davidlohr Bueso   ipc: fix race wit...
205
  	ipc_rcu_putref(shp, shm_rcu_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
207
208
  }
  
  /*
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
   * 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...
226
   * remove the attach descriptor vma.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
229
230
   * 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...
231
  static void shm_close(struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
233
234
  	struct file * file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
236
  	struct ipc_namespace *ns = sfd->ns;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
237

33b746698   Davidlohr Bueso   ipc: rename ids->...
238
  	down_write(&shm_ids(ns).rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
  	/* remove from the list of attaches of the shm segment */
00c2bf85d   Nadia Derbey   ipc: get rid of i...
240
  	shp = shm_lock(ns, sfd->id);
023a53557   Nadia Derbey   ipc: integrate ip...
241
  	BUG_ON(IS_ERR(shp));
b488893a3   Pavel Emelyanov   pid namespaces: c...
242
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
  	shp->shm_dtim = get_seconds();
  	shp->shm_nattch--;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
245
246
247
248
  	if (shm_may_destroy(ns, shp))
  		shm_destroy(ns, shp);
  	else
  		shm_unlock(shp);
33b746698   Davidlohr Bueso   ipc: rename ids->...
249
  	up_write(&shm_ids(ns).rwsem);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
250
  }
33b746698   Davidlohr Bueso   ipc: rename ids->...
251
  /* Called with ns->shm_ids(ns).rwsem locked */
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
252
253
254
  static int shm_try_destroy_current(int id, void *p, void *data)
  {
  	struct ipc_namespace *ns = data;
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
255
256
  	struct kern_ipc_perm *ipcp = p;
  	struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
257

4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
258
  	if (shp->shm_creator != current)
5774ed014   Vasiliy Kulikov   shm: handle separ...
259
  		return 0;
5774ed014   Vasiliy Kulikov   shm: handle separ...
260
261
262
263
264
265
266
267
268
269
270
271
  
  	/*
  	 * 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...
272
  	if (!ns->shm_rmid_forced)
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
273
  		return 0;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
274

4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
275
276
  	if (shm_may_destroy(ns, shp)) {
  		shm_lock_by_ptr(shp);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
277
  		shm_destroy(ns, shp);
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
278
  	}
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
279
280
  	return 0;
  }
33b746698   Davidlohr Bueso   ipc: rename ids->...
281
  /* Called with ns->shm_ids(ns).rwsem locked */
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
282
283
284
  static int shm_try_destroy_orphaned(int id, void *p, void *data)
  {
  	struct ipc_namespace *ns = data;
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
285
286
  	struct kern_ipc_perm *ipcp = p;
  	struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
287
288
289
290
  
  	/*
  	 * We want to destroy segments without users and with already
  	 * exit'ed originating process.
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
291
  	 *
33b746698   Davidlohr Bueso   ipc: rename ids->...
292
  	 * As shp->* are changed under rwsem, it's safe to skip shp locking.
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
293
  	 */
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
294
  	if (shp->shm_creator != NULL)
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
295
  		return 0;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
296

4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
297
298
  	if (shm_may_destroy(ns, shp)) {
  		shm_lock_by_ptr(shp);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
299
  		shm_destroy(ns, shp);
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
300
  	}
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
301
302
303
304
305
  	return 0;
  }
  
  void shm_destroy_orphaned(struct ipc_namespace *ns)
  {
33b746698   Davidlohr Bueso   ipc: rename ids->...
306
  	down_write(&shm_ids(ns).rwsem);
33a30ed4b   Vasiliy Kulikov   shm: fix wrong tests
307
  	if (shm_ids(ns).in_use)
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
308
  		idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns);
33b746698   Davidlohr Bueso   ipc: rename ids->...
309
  	up_write(&shm_ids(ns).rwsem);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
310
311
312
313
314
  }
  
  
  void exit_shm(struct task_struct *task)
  {
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
315
  	struct ipc_namespace *ns = task->nsproxy->ipc_ns;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
316

298507d4d   Vasiliy Kulikov   shm: optimize exi...
317
318
  	if (shm_ids(ns).in_use == 0)
  		return;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
319
  	/* Destroy all already created segments, but not mapped yet */
33b746698   Davidlohr Bueso   ipc: rename ids->...
320
  	down_write(&shm_ids(ns).rwsem);
33a30ed4b   Vasiliy Kulikov   shm: fix wrong tests
321
  	if (shm_ids(ns).in_use)
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
322
  		idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_current, ns);
33b746698   Davidlohr Bueso   ipc: rename ids->...
323
  	up_write(&shm_ids(ns).rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
  }
d0217ac04   Nick Piggin   mm: fault feedbac...
325
  static int shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
326
327
328
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
d0217ac04   Nick Piggin   mm: fault feedbac...
329
  	return sfd->vm_ops->fault(vma, vmf);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
330
331
332
  }
  
  #ifdef CONFIG_NUMA
d823e3e75   Adrian Bunk   ipc/shm.c: make 2...
333
  static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
334
335
336
337
338
339
340
341
  {
  	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...
342
343
  static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
  					unsigned long addr)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
344
345
346
347
348
349
350
  {
  	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...
351
  	else if (vma->vm_policy)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
352
  		pol = vma->vm_policy;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
353

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
354
355
356
  	return pol;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
  static int shm_mmap(struct file * file, struct vm_area_struct * vma)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
359
  	struct shm_file_data *sfd = shm_file_data(file);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
360
  	int ret;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
361
362
363
364
  	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...
365
  #ifdef CONFIG_MMU
54cb8821d   Nick Piggin   mm: merge populat...
366
  	BUG_ON(!sfd->vm_ops->fault);
2e92a3bae   David Howells   NOMMU: Fix SYSV I...
367
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
368
369
  	vma->vm_ops = &shm_vm_ops;
  	shm_open(vma);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
370
371
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
373
374
  static int shm_release(struct inode *ino, struct file *file)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
375
  	struct shm_file_data *sfd = shm_file_data(file);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
376

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
377
378
379
  	put_ipc_ns(sfd->ns);
  	shm_file_data(file) = NULL;
  	kfree(sfd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
380
381
  	return 0;
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
382
  static int shm_fsync(struct file *file, loff_t start, loff_t end, int datasync)
516dffdcd   Adam Litke   [PATCH] Fix get_u...
383
  {
516dffdcd   Adam Litke   [PATCH] Fix get_u...
384
  	struct shm_file_data *sfd = shm_file_data(file);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
385

7ea808591   Christoph Hellwig   drop unused dentr...
386
387
  	if (!sfd->file->f_op->fsync)
  		return -EINVAL;
02c24a821   Josef Bacik   fs: push i_mutex ...
388
  	return sfd->file->f_op->fsync(sfd->file, start, end, datasync);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
389
  }
7d8a45695   Will Deacon   ipc: shm: restore...
390
391
392
393
394
395
396
397
398
  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...
399
400
401
402
403
  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...
404
405
  	return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len,
  						pgoff, flags);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
406
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
407

9a32144e9   Arjan van de Ven   [PATCH] mark stru...
408
  static const struct file_operations shm_file_operations = {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
409
  	.mmap		= shm_mmap,
516dffdcd   Adam Litke   [PATCH] Fix get_u...
410
  	.fsync		= shm_fsync,
4e9823111   Kirill Korotaev   [PATCH] IPC names...
411
  	.release	= shm_release,
ed5e5894b   David Howells   nommu: fix SYSV S...
412
413
414
  #ifndef CONFIG_MMU
  	.get_unmapped_area	= shm_get_unmapped_area,
  #endif
6038f373a   Arnd Bergmann   llseek: automatic...
415
  	.llseek		= noop_llseek,
7d8a45695   Will Deacon   ipc: shm: restore...
416
  	.fallocate	= shm_fallocate,
c4caa7781   Al Viro   file ->get_unmapp...
417
418
419
420
421
422
  };
  
  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...
423
  	.get_unmapped_area	= shm_get_unmapped_area,
6038f373a   Arnd Bergmann   llseek: automatic...
424
  	.llseek		= noop_llseek,
7d8a45695   Will Deacon   ipc: shm: restore...
425
  	.fallocate	= shm_fallocate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  };
c4caa7781   Al Viro   file ->get_unmapp...
427
428
429
430
  int is_file_shm_hugepages(struct file *file)
  {
  	return file->f_op == &shm_file_operations_huge;
  }
f0f37e2f7   Alexey Dobriyan   const: mark struc...
431
  static const struct vm_operations_struct shm_vm_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
433
  	.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...
434
  	.fault	= shm_fault,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
435
436
437
  #if defined(CONFIG_NUMA)
  	.set_policy = shm_set_policy,
  	.get_policy = shm_get_policy,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
439
  #endif
  };
f4566f048   Nadia Derbey   ipc: fix wrong co...
440
441
442
443
444
  /**
   * newseg - Create a new shared memory segment
   * @ns: namespace
   * @params: ptr to the structure that contains key, size and shmflg
   *
33b746698   Davidlohr Bueso   ipc: rename ids->...
445
   * Called with shm_ids.rwsem held as a writer.
f4566f048   Nadia Derbey   ipc: fix wrong co...
446
   */
7748dbfaa   Nadia Derbey   ipc: unify the sy...
447
  static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  {
7748dbfaa   Nadia Derbey   ipc: unify the sy...
449
450
451
  	key_t key = params->key;
  	int shmflg = params->flg;
  	size_t size = params->u.size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
  	int error;
  	struct shmid_kernel *shp;
d69f3bad4   Robin Holt   ipc: sysv shared ...
454
  	size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
  	struct file * file;
  	char name[13];
  	int id;
ca16d140a   KOSAKI Motohiro   mm: don't access ...
458
  	vm_flags_t acctflag = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459

4e9823111   Kirill Korotaev   [PATCH] IPC names...
460
  	if (size < SHMMIN || size > ns->shm_ctlmax)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
  		return -EINVAL;
f66d45e99   Guy Streeter   [PATCH] correct s...
462
  	if (ns->shm_tot + numpages > ns->shm_ctlall)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
465
466
467
468
469
  		return -ENOSPC;
  
  	shp = ipc_rcu_alloc(sizeof(*shp));
  	if (!shp)
  		return -ENOMEM;
  
  	shp->shm_perm.key = key;
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
470
  	shp->shm_perm.mode = (shmflg & S_IRWXUGO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
472
473
474
475
  	shp->mlock_user = NULL;
  
  	shp->shm_perm.security = NULL;
  	error = security_shm_alloc(shp);
  	if (error) {
e84ca3337   Davidlohr Bueso   ipc: fix race wit...
476
  		ipc_rcu_putref(shp, ipc_rcu_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
478
  		return error;
  	}
9d66586f7   Eric W. Biederman   shm: fix the file...
479
  	sprintf (name, "SYSV%08x", key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  	if (shmflg & SHM_HUGETLB) {
af73e4d95   Naoya Horiguchi   hugetlbfs: fix mm...
481
482
  		struct hstate *hs = hstate_sizelog((shmflg >> SHM_HUGE_SHIFT)
  						& SHM_HUGE_MASK);
091d0d55b   Li Zefan   shm: fix null poi...
483
484
485
486
487
488
489
  		size_t hugesize;
  
  		if (!hs) {
  			error = -EINVAL;
  			goto no_file;
  		}
  		hugesize = ALIGN(size, huge_page_size(hs));
af73e4d95   Naoya Horiguchi   hugetlbfs: fix mm...
490

5a6fe1259   Mel Gorman   Do not account fo...
491
492
493
  		/* hugetlb_file_setup applies strict accounting */
  		if (shmflg & SHM_NORESERVE)
  			acctflag = VM_NORESERVE;
af73e4d95   Naoya Horiguchi   hugetlbfs: fix mm...
494
  		file = hugetlb_file_setup(name, hugesize, acctflag,
42d7395fe   Andi Kleen   mm: support more ...
495
496
  				  &shp->mlock_user, HUGETLB_SHMFS_INODE,
  				(shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
  	} else {
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
498
499
500
501
502
503
  		/*
  		 * 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...
504
  			acctflag = VM_NORESERVE;
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
505
  		file = shmem_file_setup(name, size, acctflag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
507
508
509
  	}
  	error = PTR_ERR(file);
  	if (IS_ERR(file))
  		goto no_file;
48dea404e   Pierre Peiffer   IPC: use ipc_buil...
510
  	id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
283bb7fad   Pierre Peiffer   IPC: fix error ca...
511
512
  	if (id < 0) {
  		error = id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  		goto no_id;
283bb7fad   Pierre Peiffer   IPC: fix error ca...
514
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515

b488893a3   Pavel Emelyanov   pid namespaces: c...
516
  	shp->shm_cprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
519
520
521
  	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
522
  	shp->shm_file = file;
5774ed014   Vasiliy Kulikov   shm: handle separ...
523
  	shp->shm_creator = current;
34b209241   Davidlohr Bueso   ipc: move rcu loc...
524

30475cc12   Badari Pulavarty   Restore shmid as ...
525
526
527
528
  	/*
  	 * 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_...
529
  	file_inode(file)->i_ino = shp->shm_perm.id;
551110a94   Krishnakumar R   [PATCH] hugetlb: ...
530

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

115d40dbe   Davidlohr Bueso   ipc: close open c...
534
  	ipc_unlock_object(&shp->shm_perm);
34b209241   Davidlohr Bueso   ipc: move rcu loc...
535
  	rcu_read_unlock();
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
536
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
  
  no_id:
2195d2818   Hugh Dickins   fix undefined ref...
539
  	if (is_file_hugepages(file) && shp->mlock_user)
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
540
  		user_shm_unlock(size, shp->mlock_user);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
  	fput(file);
  no_file:
e84ca3337   Davidlohr Bueso   ipc: fix race wit...
543
  	ipc_rcu_putref(shp, shm_rcu_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
  	return error;
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
546
  /*
33b746698   Davidlohr Bueso   ipc: rename ids->...
547
   * Called with shm_ids.rwsem and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
548
   */
03f02c765   Nadia Derbey   Storing ipcs into...
549
  static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
550
  {
03f02c765   Nadia Derbey   Storing ipcs into...
551
552
553
554
  	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...
555
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
556
  /*
33b746698   Davidlohr Bueso   ipc: rename ids->...
557
   * Called with shm_ids.rwsem and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
558
   */
03f02c765   Nadia Derbey   Storing ipcs into...
559
560
  static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
  				struct ipc_params *params)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
561
  {
03f02c765   Nadia Derbey   Storing ipcs into...
562
563
564
565
  	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...
566
567
568
569
  		return -EINVAL;
  
  	return 0;
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
570
  SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
572
  	struct ipc_namespace *ns;
7748dbfaa   Nadia Derbey   ipc: unify the sy...
573
574
  	struct ipc_ops shm_ops;
  	struct ipc_params shm_params;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
575
576
  
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577

7748dbfaa   Nadia Derbey   ipc: unify the sy...
578
579
580
  	shm_ops.getnew = newseg;
  	shm_ops.associate = shm_security;
  	shm_ops.more_checks = shm_more_checks;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
581

7748dbfaa   Nadia Derbey   ipc: unify the sy...
582
583
584
  	shm_params.key = key;
  	shm_params.flg = shmflg;
  	shm_params.u.size = size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585

7748dbfaa   Nadia Derbey   ipc: unify the sy...
586
  	return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
589
590
591
592
593
594
595
596
  }
  
  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...
597
  		memset(&out, 0, sizeof(out));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
  		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...
613
614
  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
615
616
617
  {
  	switch(version) {
  	case IPC_64:
016d7132f   Pierre Peiffer   IPC: get rid of t...
618
  		if (copy_from_user(out, buf, sizeof(*out)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
619
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
626
  	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...
627
628
629
  		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
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
  
  		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...
663
  /*
b79521807   Helge Deller   ipc/shm.c: add RS...
664
   * Calculate and add used RSS and swap pages of a shm.
33b746698   Davidlohr Bueso   ipc: rename ids->...
665
   * Called with shm_ids.rwsem held as a reader
b79521807   Helge Deller   ipc/shm.c: add RS...
666
667
668
669
670
   */
  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_...
671
  	inode = file_inode(shp->shm_file);
b79521807   Helge Deller   ipc/shm.c: add RS...
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
  
  	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
  	}
  }
  
  /*
33b746698   Davidlohr Bueso   ipc: rename ids->...
691
   * Called with shm_ids.rwsem held as a reader
f4566f048   Nadia Derbey   ipc: fix wrong co...
692
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
693
694
  static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
  		unsigned long *swp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
696
697
  	int next_id;
  	int total, in_use;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
  
  	*rss = 0;
  	*swp = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
701
702
703
  	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...
704
  		struct kern_ipc_perm *ipc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
  		struct shmid_kernel *shp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706

e562aebc6   Tony Battersby   ipc: make shm_get...
707
708
  		ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
  		if (ipc == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
709
  			continue;
e562aebc6   Tony Battersby   ipc: make shm_get...
710
  		shp = container_of(ipc, struct shmid_kernel, shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711

b79521807   Helge Deller   ipc/shm.c: add RS...
712
  		shm_add_rss_swap(shp, rss, swp);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
713
714
  
  		total++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
  	}
  }
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
717
  /*
33b746698   Davidlohr Bueso   ipc: rename ids->...
718
   * This function handles some shmctl commands which require the rwsem
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
719
   * to be held in write mode.
33b746698   Davidlohr Bueso   ipc: rename ids->...
720
   * NOTE: no locks must be held, the rwsem is taken inside this function.
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
721
722
723
   */
  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
724
  {
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
725
  	struct kern_ipc_perm *ipcp;
016d7132f   Pierre Peiffer   IPC: get rid of t...
726
  	struct shmid64_ds shmid64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
  	struct shmid_kernel *shp;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
728
729
730
  	int err;
  
  	if (cmd == IPC_SET) {
016d7132f   Pierre Peiffer   IPC: get rid of t...
731
  		if (copy_shmid_from_user(&shmid64, buf, version))
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
732
733
  			return -EFAULT;
  	}
33b746698   Davidlohr Bueso   ipc: rename ids->...
734
  	down_write(&shm_ids(ns).rwsem);
ac9bc6e39   Davidlohr Bueso   ipc: move locking...
735
  	rcu_read_lock();
b3b7b427f   Davidlohr Bueso   ipc,shm: shorten ...
736
737
  	ipcp = ipcctl_pre_down_nolock(ns, &shm_ids(ns), shmid, cmd,
  				      &shmid64.shm_perm, 0);
ac9bc6e39   Davidlohr Bueso   ipc: move locking...
738
739
  	if (IS_ERR(ipcp)) {
  		err = PTR_ERR(ipcp);
ac9bc6e39   Davidlohr Bueso   ipc: move locking...
740
741
  		goto out_unlock1;
  	}
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
742

a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
743
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
744
745
746
  
  	err = security_shm_shmctl(shp, cmd);
  	if (err)
b3b7b427f   Davidlohr Bueso   ipc,shm: shorten ...
747
  		goto out_unlock1;
ac9bc6e39   Davidlohr Bueso   ipc: move locking...
748

8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
749
750
  	switch (cmd) {
  	case IPC_RMID:
b3b7b427f   Davidlohr Bueso   ipc,shm: shorten ...
751
  		ipc_lock_object(&shp->shm_perm);
ac9bc6e39   Davidlohr Bueso   ipc: move locking...
752
  		/* do_shm_rmid unlocks the ipc object and rcu */
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
753
754
755
  		do_shm_rmid(ns, ipcp);
  		goto out_up;
  	case IPC_SET:
b3b7b427f   Davidlohr Bueso   ipc,shm: shorten ...
756
  		ipc_lock_object(&shp->shm_perm);
1efdb69b0   Eric W. Biederman   userns: Convert i...
757
758
  		err = ipc_update_perm(&shmid64.shm_perm, ipcp);
  		if (err)
ac9bc6e39   Davidlohr Bueso   ipc: move locking...
759
  			goto out_unlock0;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
760
761
762
763
  		shp->shm_ctim = get_seconds();
  		break;
  	default:
  		err = -EINVAL;
b3b7b427f   Davidlohr Bueso   ipc,shm: shorten ...
764
  		goto out_unlock1;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
765
  	}
ac9bc6e39   Davidlohr Bueso   ipc: move locking...
766
767
768
769
770
  
  out_unlock0:
  	ipc_unlock_object(&shp->shm_perm);
  out_unlock1:
  	rcu_read_unlock();
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
771
  out_up:
33b746698   Davidlohr Bueso   ipc: rename ids->...
772
  	up_write(&shm_ids(ns).rwsem);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
773
774
  	return err;
  }
d6187ddfc   Davidlohr Bueso   ipc,shm: introduc...
775
776
  static int shmctl_nolock(struct ipc_namespace *ns, int shmid,
  			 int cmd, int version, void __user *buf)
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
777
  {
d6187ddfc   Davidlohr Bueso   ipc,shm: introduc...
778
  	int err;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
779
  	struct shmid_kernel *shp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780

d6187ddfc   Davidlohr Bueso   ipc,shm: introduc...
781
782
783
784
785
  	/* preliminary security checks for *_INFO */
  	if (cmd == IPC_INFO || cmd == SHM_INFO) {
  		err = security_shm_shmctl(NULL, cmd);
  		if (err)
  			return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
  	}
d6187ddfc   Davidlohr Bueso   ipc,shm: introduc...
787
  	switch (cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
789
790
  	case IPC_INFO:
  	{
  		struct shminfo64 shminfo;
e8148f758   WANG Cong   ipc: clean up ipc...
791
  		memset(&shminfo, 0, sizeof(shminfo));
4e9823111   Kirill Korotaev   [PATCH] IPC names...
792
793
794
  		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
795
796
797
798
  
  		shminfo.shmmin = SHMMIN;
  		if(copy_shminfo_to_user (buf, &shminfo, version))
  			return -EFAULT;
f4566f048   Nadia Derbey   ipc: fix wrong co...
799

33b746698   Davidlohr Bueso   ipc: rename ids->...
800
  		down_read(&shm_ids(ns).rwsem);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
801
  		err = ipc_get_maxid(&shm_ids(ns));
33b746698   Davidlohr Bueso   ipc: rename ids->...
802
  		up_read(&shm_ids(ns).rwsem);
f4566f048   Nadia Derbey   ipc: fix wrong co...
803

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
807
808
809
810
  		if(err<0)
  			err = 0;
  		goto out;
  	}
  	case SHM_INFO:
  	{
  		struct shm_info shm_info;
e8148f758   WANG Cong   ipc: clean up ipc...
811
  		memset(&shm_info, 0, sizeof(shm_info));
33b746698   Davidlohr Bueso   ipc: rename ids->...
812
  		down_read(&shm_ids(ns).rwsem);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
813
814
815
  		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
816
817
  		shm_info.swap_attempts = 0;
  		shm_info.swap_successes = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
818
  		err = ipc_get_maxid(&shm_ids(ns));
33b746698   Davidlohr Bueso   ipc: rename ids->...
819
  		up_read(&shm_ids(ns).rwsem);
e8148f758   WANG Cong   ipc: clean up ipc...
820
  		if (copy_to_user(buf, &shm_info, sizeof(shm_info))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
823
824
825
826
827
828
829
830
831
832
  			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...
833

c29c40392   Davidlohr Bueso   ipc,shm: make shm...
834
  		rcu_read_lock();
023a53557   Nadia Derbey   ipc: integrate ip...
835
  		if (cmd == SHM_STAT) {
c29c40392   Davidlohr Bueso   ipc,shm: make shm...
836
  			shp = shm_obtain_object(ns, shmid);
023a53557   Nadia Derbey   ipc: integrate ip...
837
838
  			if (IS_ERR(shp)) {
  				err = PTR_ERR(shp);
c29c40392   Davidlohr Bueso   ipc,shm: make shm...
839
  				goto out_unlock;
023a53557   Nadia Derbey   ipc: integrate ip...
840
  			}
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
841
  			result = shp->shm_perm.id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
  		} else {
c29c40392   Davidlohr Bueso   ipc,shm: make shm...
843
  			shp = shm_obtain_object_check(ns, shmid);
023a53557   Nadia Derbey   ipc: integrate ip...
844
845
  			if (IS_ERR(shp)) {
  				err = PTR_ERR(shp);
c29c40392   Davidlohr Bueso   ipc,shm: make shm...
846
  				goto out_unlock;
023a53557   Nadia Derbey   ipc: integrate ip...
847
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
  			result = 0;
  		}
c29c40392   Davidlohr Bueso   ipc,shm: make shm...
850

e8148f758   WANG Cong   ipc: clean up ipc...
851
  		err = -EACCES;
b0e77598f   Serge E. Hallyn   userns: user name...
852
  		if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
  			goto out_unlock;
c29c40392   Davidlohr Bueso   ipc,shm: make shm...
854

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
856
857
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock;
c29c40392   Davidlohr Bueso   ipc,shm: make shm...
858

023a53557   Nadia Derbey   ipc: integrate ip...
859
  		memset(&tbuf, 0, sizeof(tbuf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
862
863
864
865
866
  		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...
867
  		tbuf.shm_nattch	= shp->shm_nattch;
c29c40392   Davidlohr Bueso   ipc,shm: make shm...
868
869
870
  		rcu_read_unlock();
  
  		if (copy_shmid_to_user(buf, &tbuf, version))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
872
873
874
875
  			err = -EFAULT;
  		else
  			err = result;
  		goto out;
  	}
d6187ddfc   Davidlohr Bueso   ipc,shm: introduc...
876
877
878
879
880
  	default:
  		return -EINVAL;
  	}
  
  out_unlock:
c29c40392   Davidlohr Bueso   ipc,shm: make shm...
881
  	rcu_read_unlock();
d6187ddfc   Davidlohr Bueso   ipc,shm: introduc...
882
883
884
885
886
887
888
889
890
  out:
  	return err;
  }
  
  SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
  {
  	struct shmid_kernel *shp;
  	int err, version;
  	struct ipc_namespace *ns;
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
891
892
  	if (cmd < 0 || shmid < 0)
  		return -EINVAL;
d6187ddfc   Davidlohr Bueso   ipc,shm: introduc...
893
894
895
896
897
898
899
900
901
902
  
  	version = ipc_parse_version(&cmd);
  	ns = current->nsproxy->ipc_ns;
  
  	switch (cmd) {
  	case IPC_INFO:
  	case SHM_INFO:
  	case SHM_STAT:
  	case IPC_STAT:
  		return shmctl_nolock(ns, shmid, cmd, version, buf);
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
903
904
905
  	case IPC_RMID:
  	case IPC_SET:
  		return shmctl_down(ns, shmid, cmd, buf, version);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
908
  	case SHM_LOCK:
  	case SHM_UNLOCK:
  	{
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
909
  		struct file *shm_file;
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
910

00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
911
912
  		rcu_read_lock();
  		shp = shm_obtain_object_check(ns, shmid);
023a53557   Nadia Derbey   ipc: integrate ip...
913
914
  		if (IS_ERR(shp)) {
  			err = PTR_ERR(shp);
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
915
  			goto out_unlock1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
917

a33e67510   Al Viro   sanitize audit_ip...
918
  		audit_ipc_obj(&(shp->shm_perm));
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
919
920
921
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock1;
073115d6b   Steve Grubb   [PATCH] Rework of...
922

00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
923
  		ipc_lock_object(&shp->shm_perm);
b0e77598f   Serge E. Hallyn   userns: user name...
924
  		if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
1efdb69b0   Eric W. Biederman   userns: Convert i...
925
  			kuid_t euid = current_euid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
  			err = -EPERM;
1efdb69b0   Eric W. Biederman   userns: Convert i...
927
928
  			if (!uid_eq(euid, shp->shm_perm.uid) &&
  			    !uid_eq(euid, shp->shm_perm.cuid))
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
929
  				goto out_unlock0;
f1eb1332b   Jiri Slaby   ipc: use rlimit h...
930
  			if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
931
  				goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
  		}
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
933
934
  		shm_file = shp->shm_file;
  		if (is_file_hugepages(shm_file))
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
935
  			goto out_unlock0;
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
936
937
  
  		if (cmd == SHM_LOCK) {
86a264abe   David Howells   CRED: Wrap curren...
938
  			struct user_struct *user = current_user();
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
939
940
941
942
  			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
943
  			}
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
944
  			goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
  		}
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
946
947
948
  
  		/* SHM_UNLOCK */
  		if (!(shp->shm_perm.mode & SHM_LOCKED))
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
949
  			goto out_unlock0;
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
950
951
952
953
  		shmem_lock(shm_file, 0, shp->mlock_user);
  		shp->shm_perm.mode &= ~SHM_LOCKED;
  		shp->mlock_user = NULL;
  		get_file(shm_file);
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
954
955
  		ipc_unlock_object(&shp->shm_perm);
  		rcu_read_unlock();
245132643   Hugh Dickins   SHM_UNLOCK: fix U...
956
  		shmem_unlock_mapping(shm_file->f_mapping);
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
957

85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
958
  		fput(shm_file);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
959
  		return err;
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
960
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
961
  	default:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
962
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
963
  	}
00c88e695   Davidlohr Bueso   ipc,shm: shorten ...
964
965
966
967
  out_unlock0:
  	ipc_unlock_object(&shp->shm_perm);
  out_unlock1:
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
969
970
971
972
973
974
975
976
977
  	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...
978
979
  long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
  	      unsigned long shmlba)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
980
981
982
983
984
985
986
987
  {
  	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
988
  	int acc_mode;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
989
  	struct ipc_namespace *ns;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
990
991
  	struct shm_file_data *sfd;
  	struct path path;
aeb5d7270   Al Viro   [PATCH] introduce...
992
  	fmode_t f_mode;
41badc15c   Michel Lespinasse   mm: make do_mmap_...
993
  	unsigned long populate = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
995
996
  	err = -EINVAL;
  	if (shmid < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997
  		goto out;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
998
  	else if ((addr = (ulong)shmaddr)) {
079a96ae3   Will Deacon   ipc: add COMPAT_S...
999
  		if (addr & (shmlba - 1)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
  			if (shmflg & SHM_RND)
079a96ae3   Will Deacon   ipc: add COMPAT_S...
1001
  				addr &= ~(shmlba - 1);	   /* round down */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1002
1003
1004
1005
  			else
  #ifndef __ARCH_FORCE_SHMLBA
  				if (addr & ~PAGE_MASK)
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1006
  					goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
1010
  		}
  		flags = MAP_SHARED | MAP_FIXED;
  	} else {
  		if ((shmflg & SHM_REMAP))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1011
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012
1013
1014
1015
1016
1017
  
  		flags = MAP_SHARED;
  	}
  
  	if (shmflg & SHM_RDONLY) {
  		prot = PROT_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
  		acc_mode = S_IRUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1019
  		f_mode = FMODE_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1020
1021
  	} else {
  		prot = PROT_READ | PROT_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
  		acc_mode = S_IRUGO | S_IWUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1023
  		f_mode = FMODE_READ | FMODE_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
  	}
  	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...
1034
  	ns = current->nsproxy->ipc_ns;
bd58e2dc2   Davidlohr Bueso   ipc,shm: shorten ...
1035
1036
  	rcu_read_lock();
  	shp = shm_obtain_object_check(ns, shmid);
023a53557   Nadia Derbey   ipc: integrate ip...
1037
1038
  	if (IS_ERR(shp)) {
  		err = PTR_ERR(shp);
bd58e2dc2   Davidlohr Bueso   ipc,shm: shorten ...
1039
  		goto out_unlock;
023a53557   Nadia Derbey   ipc: integrate ip...
1040
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1041
1042
  
  	err = -EACCES;
b0e77598f   Serge E. Hallyn   userns: user name...
1043
  	if (ipcperms(ns, &shp->shm_perm, acc_mode))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1044
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
1046
  
  	err = security_shm_shmat(shp, shmaddr, shmflg);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1047
1048
  	if (err)
  		goto out_unlock;
bd58e2dc2   Davidlohr Bueso   ipc,shm: shorten ...
1049
  	ipc_lock_object(&shp->shm_perm);
2c48b9c45   Al Viro   switch alloc_file...
1050
1051
  	path = shp->shm_file->f_path;
  	path_get(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1052
  	shp->shm_nattch++;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1053
  	size = i_size_read(path.dentry->d_inode);
bd58e2dc2   Davidlohr Bueso   ipc,shm: shorten ...
1054
1055
  	ipc_unlock_object(&shp->shm_perm);
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1056

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1057
1058
  	err = -ENOMEM;
  	sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
247ec302b   Davidlohr Bueso   ipc,shm: cleanup ...
1059
1060
1061
1062
  	if (!sfd) {
  		path_put(&path);
  		goto out_nattch;
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1063

2c48b9c45   Al Viro   switch alloc_file...
1064
1065
  	file = alloc_file(&path, f_mode,
  			  is_file_hugepages(shp->shm_file) ?
c4caa7781   Al Viro   file ->get_unmapp...
1066
1067
  				&shm_file_operations_huge :
  				&shm_file_operations);
39b652527   Anatol Pomozov   fs: Preserve erro...
1068
  	err = PTR_ERR(file);
247ec302b   Davidlohr Bueso   ipc,shm: cleanup ...
1069
1070
1071
1072
1073
  	if (IS_ERR(file)) {
  		kfree(sfd);
  		path_put(&path);
  		goto out_nattch;
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1074

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1075
  	file->private_data = sfd;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1076
  	file->f_mapping = shp->shm_file->f_mapping;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
1077
  	sfd->id = shp->shm_perm.id;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1078
1079
1080
  	sfd->ns = get_ipc_ns(ns);
  	sfd->file = shp->shm_file;
  	sfd->vm_ops = NULL;
8b3ec6814   Al Viro   take security_mma...
1081
1082
1083
  	err = security_mmap_file(file, prot, flags);
  	if (err)
  		goto out_fput;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
1085
  	down_write(&current->mm->mmap_sem);
  	if (addr && !(shmflg & SHM_REMAP)) {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1086
  		err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
  		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;
  	}
247ec302b   Davidlohr Bueso   ipc,shm: cleanup ...
1097

bebeb3d68   Michel Lespinasse   mm: introduce mm_...
1098
1099
  	addr = do_mmap_pgoff(file, addr, size, prot, flags, 0, &populate);
  	*raddr = addr;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1100
  	err = 0;
bebeb3d68   Michel Lespinasse   mm: introduce mm_...
1101
1102
  	if (IS_ERR_VALUE(addr))
  		err = (long)addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
1104
  invalid:
  	up_write(&current->mm->mmap_sem);
bebeb3d68   Michel Lespinasse   mm: introduce mm_...
1105
  	if (populate)
41badc15c   Michel Lespinasse   mm: make do_mmap_...
1106
  		mm_populate(addr, populate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107

8b3ec6814   Al Viro   take security_mma...
1108
  out_fput:
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1109
1110
1111
  	fput(file);
  
  out_nattch:
33b746698   Davidlohr Bueso   ipc: rename ids->...
1112
  	down_write(&shm_ids(ns).rwsem);
00c2bf85d   Nadia Derbey   ipc: get rid of i...
1113
  	shp = shm_lock(ns, shmid);
023a53557   Nadia Derbey   ipc: integrate ip...
1114
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1115
  	shp->shm_nattch--;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
1116
  	if (shm_may_destroy(ns, shp))
4e9823111   Kirill Korotaev   [PATCH] IPC names...
1117
  		shm_destroy(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1118
1119
  	else
  		shm_unlock(shp);
33b746698   Davidlohr Bueso   ipc: rename ids->...
1120
  	up_write(&shm_ids(ns).rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121
  	return err;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1122
1123
  
  out_unlock:
bd58e2dc2   Davidlohr Bueso   ipc,shm: shorten ...
1124
  	rcu_read_unlock();
247ec302b   Davidlohr Bueso   ipc,shm: cleanup ...
1125
1126
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1127
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
1128
  SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
1129
1130
1131
  {
  	unsigned long ret;
  	long err;
079a96ae3   Will Deacon   ipc: add COMPAT_S...
1132
  	err = do_shmat(shmid, shmaddr, shmflg, &ret, SHMLBA);
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
1133
1134
1135
1136
1137
  	if (err)
  		return err;
  	force_successful_syscall_return();
  	return (long)ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
1139
1140
1141
  /*
   * detach and kill segment if marked destroyed.
   * The work is done in shm_close.
   */
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
1142
  SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1143
1144
  {
  	struct mm_struct *mm = current->mm;
586c7e6a2   Mike Frysinger   shm: fix unused w...
1145
  	struct vm_area_struct *vma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1146
  	unsigned long addr = (unsigned long)shmaddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1147
  	int retval = -EINVAL;
586c7e6a2   Mike Frysinger   shm: fix unused w...
1148
1149
1150
1151
  #ifdef CONFIG_MMU
  	loff_t size = 0;
  	struct vm_area_struct *next;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1152

df1e2fb54   Hugh Dickins   [PATCH] shmdt: ch...
1153
1154
  	if (addr & ~PAGE_MASK)
  		return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
  	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 ...
1178
  #ifdef CONFIG_MMU
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1179
1180
1181
1182
1183
1184
1185
1186
  	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...
1187
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1188
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
496ad9aa8   Al Viro   new helper: file_...
1189
  			size = file_inode(vma->vm_file)->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
  			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...
1207
  	 * prevent overflows and make comparisons vs. equal-width types.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1208
  	 */
8e36709d8   KAMEZAWA Hiroyuki   [PATCH] shmdt can...
1209
  	size = PAGE_ALIGN(size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210
1211
1212
1213
  	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...
1214
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1215
1216
1217
1218
1219
  			(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 ...
1220
1221
1222
  #else /* CONFIG_MMU */
  	/* under NOMMU conditions, the exact address to be destroyed must be
  	 * given */
48ec782ce   Davidlohr Bueso   ipc, shm: guard a...
1223
  	if (vma && vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) {
8feae1311   David Howells   NOMMU: Make VMAs ...
1224
1225
1226
1227
1228
  		do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
  		retval = 0;
  	}
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1229
1230
1231
1232
1233
  	up_write(&mm->mmap_sem);
  	return retval;
  }
  
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1234
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
  {
1efdb69b0   Eric W. Biederman   userns: Convert i...
1236
  	struct user_namespace *user_ns = seq_user_ns(s);
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1237
  	struct shmid_kernel *shp = it;
b79521807   Helge Deller   ipc/shm.c: add RS...
1238
1239
1240
  	unsigned long rss = 0, swp = 0;
  
  	shm_add_rss_swap(shp, &rss, &swp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1241

6c826818f   Paul Menage   /proc/sysvipc/shm...
1242
1243
1244
1245
1246
  #if BITS_PER_LONG <= 32
  #define SIZE_SPEC "%10lu"
  #else
  #define SIZE_SPEC "%21lu"
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247

6c826818f   Paul Menage   /proc/sysvipc/shm...
1248
1249
  	return seq_printf(s,
  			  "%10d %10d  %4o " SIZE_SPEC " %5u %5u  "
b79521807   Helge Deller   ipc/shm.c: add RS...
1250
1251
1252
  			  "%5lu %5u %5u %5u %5u %10lu %10lu %10lu "
  			  SIZE_SPEC " " SIZE_SPEC "
  ",
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1253
  			  shp->shm_perm.key,
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
1254
  			  shp->shm_perm.id,
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
1255
  			  shp->shm_perm.mode,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1256
1257
1258
  			  shp->shm_segsz,
  			  shp->shm_cprid,
  			  shp->shm_lprid,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1259
  			  shp->shm_nattch,
1efdb69b0   Eric W. Biederman   userns: Convert i...
1260
1261
1262
1263
  			  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...
1264
1265
  			  shp->shm_atim,
  			  shp->shm_dtim,
b79521807   Helge Deller   ipc/shm.c: add RS...
1266
1267
1268
  			  shp->shm_ctim,
  			  rss * PAGE_SIZE,
  			  swp * PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269
1270
  }
  #endif