Blame view

ipc/shm.c 39.5 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  /*
   * 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...
17
18
   * support for audit of ipc object properties and permission changes
   * Dustin Kirkland <dustin.kirkland@us.ibm.com>
4e9823111   Kirill Korotaev   [PATCH] IPC names...
19
20
21
22
   *
   * namespaces support
   * OpenVZ, SWsoft Inc.
   * Pavel Emelianov <xemul@openvz.org>
c2c737a04   Davidlohr Bueso   ipc,shm: shorten ...
23
24
25
   *
   * Better ipc lock (kern_ipc_perm.lock) handling
   * Davidlohr Bueso <davidlohr.bueso@hp.com>, June 2013.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
31
32
33
  #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
34
35
36
37
  #include <linux/shmem_fs.h>
  #include <linux/security.h>
  #include <linux/syscalls.h>
  #include <linux/audit.h>
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
38
  #include <linux/capability.h>
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
39
  #include <linux/ptrace.h>
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
40
  #include <linux/seq_file.h>
3e148c799   Nadia Derbey   fix idr_find() lo...
41
  #include <linux/rwsem.h>
4e9823111   Kirill Korotaev   [PATCH] IPC names...
42
  #include <linux/nsproxy.h>
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
43
  #include <linux/mount.h>
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
44
  #include <linux/ipc_namespace.h>
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
45

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

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

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

7748dbfaa   Nadia Derbey   ipc: unify the sy...
65
  static int newseg(struct ipc_namespace *, struct ipc_params *);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
66
67
  static void shm_open(struct vm_area_struct *vma);
  static void shm_close(struct vm_area_struct *vma);
239521f31   Manfred Spraul   ipc: whitespace c...
68
  static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
70
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
  #endif
0cfb6aee7   Guillaume Knispel   ipc: optimize sem...
72
  int shm_init_ns(struct ipc_namespace *ns)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
73
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
74
75
76
  	ns->shm_ctlmax = SHMMAX;
  	ns->shm_ctlall = SHMALL;
  	ns->shm_ctlmni = SHMMNI;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
77
  	ns->shm_rmid_forced = 0;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
78
  	ns->shm_tot = 0;
0cfb6aee7   Guillaume Knispel   ipc: optimize sem...
79
  	return ipc_init_ids(&shm_ids(ns));
4e9823111   Kirill Korotaev   [PATCH] IPC names...
80
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
81
  /*
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
82
83
   * 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...
84
   */
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
85
  static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
86
  {
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
87
  	struct shmid_kernel *shp;
63980c80e   Shailesh Pandey   ipc/shm.c: coding...
88

01b8b07a5   Pierre Peiffer   IPC: consolidate ...
89
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
239521f31   Manfred Spraul   ipc: whitespace c...
90
  	if (shp->shm_nattch) {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
91
92
  		shp->shm_perm.mode |= SHM_DEST;
  		/* Do not find it any more */
0cfb6aee7   Guillaume Knispel   ipc: optimize sem...
93
  		ipc_set_key_private(&shm_ids(ns), &shp->shm_perm);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
94
95
96
97
  		shm_unlock(shp);
  	} else
  		shm_destroy(ns, shp);
  }
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
98
  #ifdef CONFIG_IPC_NS
4e9823111   Kirill Korotaev   [PATCH] IPC names...
99
100
  void shm_exit_ns(struct ipc_namespace *ns)
  {
01b8b07a5   Pierre Peiffer   IPC: consolidate ...
101
  	free_ipcs(ns, &shm_ids(ns), do_shm_rmid);
7d6feeb28   Serge E. Hallyn   ipc ns: fix memor...
102
  	idr_destroy(&ns->ids[IPC_SHM_IDS].ipcs_idr);
0cfb6aee7   Guillaume Knispel   ipc: optimize sem...
103
  	rhashtable_destroy(&ns->ids[IPC_SHM_IDS].key_ht);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
104
  }
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
105
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106

140d0b210   Linus Torvalds   Do 'shm_init_ns()...
107
  static int __init ipc_ns_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
  {
0cfb6aee7   Guillaume Knispel   ipc: optimize sem...
109
110
111
112
  	const int err = shm_init_ns(&init_ipc_ns);
  	WARN(err, "ipc: sysv shm_init_ns failed: %d
  ", err);
  	return err;
140d0b210   Linus Torvalds   Do 'shm_init_ns()...
113
114
115
  }
  
  pure_initcall(ipc_ns_init);
239521f31   Manfred Spraul   ipc: whitespace c...
116
  void __init shm_init(void)
140d0b210   Linus Torvalds   Do 'shm_init_ns()...
117
  {
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
118
  	ipc_init_proc_interface("sysvipc/shm",
b79521807   Helge Deller   ipc/shm.c: add RS...
119
120
121
122
123
124
125
  #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...
126
  				IPC_SHM_IDS, sysvipc_shm_proc_show);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
  }
8b8d52ac3   Davidlohr Bueso   ipc,shm: introduc...
128
129
  static inline struct shmid_kernel *shm_obtain_object(struct ipc_namespace *ns, int id)
  {
55b7ae501   Davidlohr Bueso   ipc: rename ipc_o...
130
  	struct kern_ipc_perm *ipcp = ipc_obtain_object_idr(&shm_ids(ns), id);
8b8d52ac3   Davidlohr Bueso   ipc,shm: introduc...
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  
  	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...
147
  /*
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
148
   * shm_lock_(check_) routines are called in the paths where the rwsem
00c2bf85d   Nadia Derbey   ipc: get rid of i...
149
   * is not necessarily held.
3e148c799   Nadia Derbey   fix idr_find() lo...
150
   */
023a53557   Nadia Derbey   ipc: integrate ip...
151
  static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  {
03f02c765   Nadia Derbey   Storing ipcs into...
153
  	struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id);
c5c8975b2   Davidlohr Bueso   ipc,shm: move BUG...
154
  	/*
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
155
156
157
  	 * Callers of shm_lock() must validate the status of the returned ipc
  	 * object pointer (as returned by ipc_lock()), and error out as
  	 * appropriate.
c5c8975b2   Davidlohr Bueso   ipc,shm: move BUG...
158
  	 */
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
159
160
  	if (IS_ERR(ipcp))
  		return (void *)ipcp;
03f02c765   Nadia Derbey   Storing ipcs into...
161
  	return container_of(ipcp, struct shmid_kernel, shm_perm);
023a53557   Nadia Derbey   ipc: integrate ip...
162
  }
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
163
164
165
  static inline void shm_lock_by_ptr(struct shmid_kernel *ipcp)
  {
  	rcu_read_lock();
cf9d5d78d   Davidlohr Bueso   ipc: close open c...
166
  	ipc_lock_object(&ipcp->shm_perm);
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
167
  }
53dad6d3a   Davidlohr Bueso   ipc: fix race wit...
168
169
  static void shm_rcu_free(struct rcu_head *head)
  {
dba4cdd39   Manfred Spraul   ipc: merge ipc_rc...
170
171
172
173
  	struct kern_ipc_perm *ptr = container_of(head, struct kern_ipc_perm,
  							rcu);
  	struct shmid_kernel *shp = container_of(ptr, struct shmid_kernel,
  							shm_perm);
53dad6d3a   Davidlohr Bueso   ipc: fix race wit...
174
  	security_shm_free(shp);
42e618f77   Kees Cook   ipc/shm: remove s...
175
  	kvfree(shp);
53dad6d3a   Davidlohr Bueso   ipc: fix race wit...
176
  }
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
177
  static inline void shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *s)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  {
ab602f799   Jack Miller   shm: make exit_sh...
179
  	list_del(&s->shm_clist);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
180
  	ipc_rmid(&shm_ids(ns), &s->shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182

1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
183
  static int __shm_open(struct vm_area_struct *vma)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
184
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
185
186
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
188
  	shp = shm_lock(sfd->ns, sfd->id);
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
189
190
191
  
  	if (IS_ERR(shp))
  		return PTR_ERR(shp);
703eee654   Eric Biggers   ipc/shm: fix use-...
192
193
194
195
196
  	if (shp->shm_file != sfd->file) {
  		/* ID was reused */
  		shm_unlock(shp);
  		return -EINVAL;
  	}
7ff2819e8   Deepa Dinamani   ipc: shm: Make sh...
197
  	shp->shm_atim = ktime_get_real_seconds();
b488893a3   Pavel Emelyanov   pid namespaces: c...
198
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199
200
  	shp->shm_nattch++;
  	shm_unlock(shp);
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
201
202
203
204
205
206
207
208
209
210
211
212
  	return 0;
  }
  
  /* This is called by fork, once for every shm attach. */
  static void shm_open(struct vm_area_struct *vma)
  {
  	int err = __shm_open(vma);
  	/*
  	 * We raced in the idr lookup or with shm_destroy().
  	 * Either way, the ID is busted.
  	 */
  	WARN_ON_ONCE(err);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
216
  /*
   * shm_destroy - free the struct shmid_kernel
   *
f4566f048   Nadia Derbey   ipc: fix wrong co...
217
   * @ns: namespace
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
   * @shp: struct to free
   *
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
220
   * It has to be called with shp and shm_ids.rwsem (writer) locked,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
   * but returns with shp unlocked and freed.
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
223
  static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
224
  {
a399b29df   Greg Thelen   ipc,shm: fix shm_...
225
226
227
228
  	struct file *shm_file;
  
  	shm_file = shp->shm_file;
  	shp->shm_file = NULL;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
229
  	ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
230
  	shm_rmid(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
  	shm_unlock(shp);
a399b29df   Greg Thelen   ipc,shm: fix shm_...
232
233
  	if (!is_file_hugepages(shm_file))
  		shmem_lock(shm_file, 0, shp->mlock_user);
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
234
  	else if (shp->mlock_user)
07a46ed27   Dave Hansen   shmdt: use i_size...
235
236
  		user_shm_unlock(i_size_read(file_inode(shm_file)),
  				shp->mlock_user);
a399b29df   Greg Thelen   ipc,shm: fix shm_...
237
  	fput(shm_file);
dba4cdd39   Manfred Spraul   ipc: merge ipc_rc...
238
  	ipc_rcu_putref(&shp->shm_perm, shm_rcu_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
  }
  
  /*
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
   * 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...
259
   * remove the attach descriptor vma.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
263
   * 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...
264
  static void shm_close(struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
  {
239521f31   Manfred Spraul   ipc: whitespace c...
266
  	struct file *file = vma->vm_file;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
267
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
269
  	struct ipc_namespace *ns = sfd->ns;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
270

d9a605e40   Davidlohr Bueso   ipc: rename ids->...
271
  	down_write(&shm_ids(ns).rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  	/* remove from the list of attaches of the shm segment */
00c2bf85d   Nadia Derbey   ipc: get rid of i...
273
  	shp = shm_lock(ns, sfd->id);
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
274
275
276
277
278
279
280
  
  	/*
  	 * We raced in the idr lookup or with shm_destroy().
  	 * Either way, the ID is busted.
  	 */
  	if (WARN_ON_ONCE(IS_ERR(shp)))
  		goto done; /* no-op */
b488893a3   Pavel Emelyanov   pid namespaces: c...
281
  	shp->shm_lprid = task_tgid_vnr(current);
7ff2819e8   Deepa Dinamani   ipc: shm: Make sh...
282
  	shp->shm_dtim = ktime_get_real_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  	shp->shm_nattch--;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
284
285
286
287
  	if (shm_may_destroy(ns, shp))
  		shm_destroy(ns, shp);
  	else
  		shm_unlock(shp);
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
288
  done:
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
289
  	up_write(&shm_ids(ns).rwsem);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
290
  }
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
291
  /* Called with ns->shm_ids(ns).rwsem locked */
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
292
293
294
  static int shm_try_destroy_orphaned(int id, void *p, void *data)
  {
  	struct ipc_namespace *ns = data;
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
295
296
  	struct kern_ipc_perm *ipcp = p;
  	struct shmid_kernel *shp = container_of(ipcp, struct shmid_kernel, shm_perm);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
297
298
299
300
  
  	/*
  	 * We want to destroy segments without users and with already
  	 * exit'ed originating process.
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
301
  	 *
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
302
  	 * As shp->* are changed under rwsem, it's safe to skip shp locking.
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
303
  	 */
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
304
  	if (shp->shm_creator != NULL)
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
305
  		return 0;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
306

4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
307
308
  	if (shm_may_destroy(ns, shp)) {
  		shm_lock_by_ptr(shp);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
309
  		shm_destroy(ns, shp);
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
310
  	}
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
311
312
313
314
315
  	return 0;
  }
  
  void shm_destroy_orphaned(struct ipc_namespace *ns)
  {
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
316
  	down_write(&shm_ids(ns).rwsem);
33a30ed4b   Vasiliy Kulikov   shm: fix wrong tests
317
  	if (shm_ids(ns).in_use)
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
318
  		idr_for_each(&shm_ids(ns).ipcs_idr, &shm_try_destroy_orphaned, ns);
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
319
  	up_write(&shm_ids(ns).rwsem);
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
320
  }
83293c0f5   Jack Miller   shm: allow exit_s...
321
  /* Locking assumes this will only be called with task == current */
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
322
323
  void exit_shm(struct task_struct *task)
  {
4c677e2ee   Vasiliy Kulikov   shm: optimize loc...
324
  	struct ipc_namespace *ns = task->nsproxy->ipc_ns;
ab602f799   Jack Miller   shm: make exit_sh...
325
  	struct shmid_kernel *shp, *n;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
326

83293c0f5   Jack Miller   shm: allow exit_s...
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  	if (list_empty(&task->sysvshm.shm_clist))
  		return;
  
  	/*
  	 * If kernel.shm_rmid_forced is not set then only keep track of
  	 * which shmids are orphaned, so that a later set of the sysctl
  	 * can clean them up.
  	 */
  	if (!ns->shm_rmid_forced) {
  		down_read(&shm_ids(ns).rwsem);
  		list_for_each_entry(shp, &task->sysvshm.shm_clist, shm_clist)
  			shp->shm_creator = NULL;
  		/*
  		 * Only under read lock but we are only called on current
  		 * so no entry on the list will be shared.
  		 */
  		list_del(&task->sysvshm.shm_clist);
  		up_read(&shm_ids(ns).rwsem);
298507d4d   Vasiliy Kulikov   shm: optimize exi...
345
  		return;
83293c0f5   Jack Miller   shm: allow exit_s...
346
  	}
298507d4d   Vasiliy Kulikov   shm: optimize exi...
347

83293c0f5   Jack Miller   shm: allow exit_s...
348
349
350
351
352
  	/*
  	 * Destroy all already created segments, that were not yet mapped,
  	 * and mark any mapped as orphan to cover the sysctl toggling.
  	 * Destroy is skipped if shm_may_destroy() returns false.
  	 */
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
353
  	down_write(&shm_ids(ns).rwsem);
83293c0f5   Jack Miller   shm: allow exit_s...
354
355
356
357
358
359
360
361
362
363
  	list_for_each_entry_safe(shp, n, &task->sysvshm.shm_clist, shm_clist) {
  		shp->shm_creator = NULL;
  
  		if (shm_may_destroy(ns, shp)) {
  			shm_lock_by_ptr(shp);
  			shm_destroy(ns, shp);
  		}
  	}
  
  	/* Remove the list head from any segments still attached. */
ab602f799   Jack Miller   shm: make exit_sh...
364
  	list_del(&task->sysvshm.shm_clist);
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
365
  	up_write(&shm_ids(ns).rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  }
11bac8000   Dave Jiang   mm, fs: reduce fa...
367
  static int shm_fault(struct vm_fault *vmf)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
368
  {
11bac8000   Dave Jiang   mm, fs: reduce fa...
369
  	struct file *file = vmf->vma->vm_file;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
370
  	struct shm_file_data *sfd = shm_file_data(file);
11bac8000   Dave Jiang   mm, fs: reduce fa...
371
  	return sfd->vm_ops->fault(vmf);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
372
  }
f025072cb   Mike Kravetz   ipc/shm.c: add sp...
373
374
375
376
377
378
379
380
381
382
  static int shm_split(struct vm_area_struct *vma, unsigned long addr)
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
  
  	if (sfd->vm_ops && sfd->vm_ops->split)
  		return sfd->vm_ops->split(vma, addr);
  
  	return 0;
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
383
  #ifdef CONFIG_NUMA
d823e3e75   Adrian Bunk   ipc/shm.c: make 2...
384
  static int shm_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
385
386
387
388
  {
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
  	int err = 0;
63980c80e   Shailesh Pandey   ipc/shm.c: coding...
389

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
390
391
392
393
  	if (sfd->vm_ops->set_policy)
  		err = sfd->vm_ops->set_policy(vma, new);
  	return err;
  }
d823e3e75   Adrian Bunk   ipc/shm.c: make 2...
394
395
  static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
  					unsigned long addr)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
396
397
398
399
400
401
402
  {
  	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...
403
  	else if (vma->vm_policy)
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
404
  		pol = vma->vm_policy;
52cd3b074   Lee Schermerhorn   mempolicy: rework...
405

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
406
407
408
  	return pol;
  }
  #endif
239521f31   Manfred Spraul   ipc: whitespace c...
409
  static int shm_mmap(struct file *file, struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
411
  	struct shm_file_data *sfd = shm_file_data(file);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
412
  	int ret;
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
413
  	/*
703eee654   Eric Biggers   ipc/shm: fix use-...
414
415
416
  	 * In case of remap_file_pages() emulation, the file can represent an
  	 * IPC ID that was removed, and possibly even reused by another shm
  	 * segment already.  Propagate this case as an error to caller.
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
417
  	 */
63980c80e   Shailesh Pandey   ipc/shm.c: coding...
418
  	ret = __shm_open(vma);
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
419
420
  	if (ret)
  		return ret;
f74ac0152   Miklos Szeredi   mm: use helper fo...
421
  	ret = call_mmap(sfd->file, vma);
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
422
423
  	if (ret) {
  		shm_close(vma);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
424
  		return ret;
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
425
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
426
  	sfd->vm_ops = vma->vm_ops;
2e92a3bae   David Howells   NOMMU: Fix SYSV I...
427
  #ifdef CONFIG_MMU
d0edd8528   Davidlohr Bueso   ipc: convert inva...
428
  	WARN_ON(!sfd->vm_ops->fault);
2e92a3bae   David Howells   NOMMU: Fix SYSV I...
429
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
430
  	vma->vm_ops = &shm_vm_ops;
1ac0b6dec   Kirill A. Shutemov   ipc/shm: handle r...
431
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
433
434
  static int shm_release(struct inode *ino, struct file *file)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
435
  	struct shm_file_data *sfd = shm_file_data(file);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
436

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
437
  	put_ipc_ns(sfd->ns);
703eee654   Eric Biggers   ipc/shm: fix use-...
438
  	fput(sfd->file);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
439
440
  	shm_file_data(file) = NULL;
  	kfree(sfd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
441
442
  	return 0;
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
443
  static int shm_fsync(struct file *file, loff_t start, loff_t end, int datasync)
516dffdcd   Adam Litke   [PATCH] Fix get_u...
444
  {
516dffdcd   Adam Litke   [PATCH] Fix get_u...
445
  	struct shm_file_data *sfd = shm_file_data(file);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
446

7ea808591   Christoph Hellwig   drop unused dentr...
447
448
  	if (!sfd->file->f_op->fsync)
  		return -EINVAL;
0f41074a6   Jeff Layton   fs: remove call_f...
449
  	return sfd->file->f_op->fsync(sfd->file, start, end, datasync);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
450
  }
7d8a45695   Will Deacon   ipc: shm: restore...
451
452
453
454
455
456
457
458
459
  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...
460
461
462
463
464
  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);
63980c80e   Shailesh Pandey   ipc/shm.c: coding...
465

c4caa7781   Al Viro   file ->get_unmapp...
466
467
  	return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len,
  						pgoff, flags);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
468
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
469

9a32144e9   Arjan van de Ven   [PATCH] mark stru...
470
  static const struct file_operations shm_file_operations = {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
471
  	.mmap		= shm_mmap,
516dffdcd   Adam Litke   [PATCH] Fix get_u...
472
  	.fsync		= shm_fsync,
4e9823111   Kirill Korotaev   [PATCH] IPC names...
473
  	.release	= shm_release,
ed5e5894b   David Howells   nommu: fix SYSV S...
474
  	.get_unmapped_area	= shm_get_unmapped_area,
6038f373a   Arnd Bergmann   llseek: automatic...
475
  	.llseek		= noop_llseek,
7d8a45695   Will Deacon   ipc: shm: restore...
476
  	.fallocate	= shm_fallocate,
c4caa7781   Al Viro   file ->get_unmapp...
477
  };
c01d5b300   Hugh Dickins   shmem: get_unmapp...
478
479
480
481
  /*
   * shm_file_operations_huge is now identical to shm_file_operations,
   * but we keep it distinct for the sake of is_file_shm_hugepages().
   */
c4caa7781   Al Viro   file ->get_unmapp...
482
483
484
485
  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...
486
  	.get_unmapped_area	= shm_get_unmapped_area,
6038f373a   Arnd Bergmann   llseek: automatic...
487
  	.llseek		= noop_llseek,
7d8a45695   Will Deacon   ipc: shm: restore...
488
  	.fallocate	= shm_fallocate,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
  };
2954e440b   Yaowei Bai   ipc/shm.c: is_fil...
490
  bool is_file_shm_hugepages(struct file *file)
c4caa7781   Al Viro   file ->get_unmapp...
491
492
493
  {
  	return file->f_op == &shm_file_operations_huge;
  }
f0f37e2f7   Alexey Dobriyan   const: mark struc...
494
  static const struct vm_operations_struct shm_vm_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
  	.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...
497
  	.fault	= shm_fault,
f025072cb   Mike Kravetz   ipc/shm.c: add sp...
498
  	.split	= shm_split,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
499
500
501
  #if defined(CONFIG_NUMA)
  	.set_policy = shm_set_policy,
  	.get_policy = shm_get_policy,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
503
  #endif
  };
f4566f048   Nadia Derbey   ipc: fix wrong co...
504
505
506
507
508
  /**
   * newseg - Create a new shared memory segment
   * @ns: namespace
   * @params: ptr to the structure that contains key, size and shmflg
   *
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
509
   * Called with shm_ids.rwsem held as a writer.
f4566f048   Nadia Derbey   ipc: fix wrong co...
510
   */
7748dbfaa   Nadia Derbey   ipc: unify the sy...
511
  static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
  {
7748dbfaa   Nadia Derbey   ipc: unify the sy...
513
514
515
  	key_t key = params->key;
  	int shmflg = params->flg;
  	size_t size = params->u.size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
  	int error;
  	struct shmid_kernel *shp;
d69f3bad4   Robin Holt   ipc: sysv shared ...
518
  	size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
239521f31   Manfred Spraul   ipc: whitespace c...
519
  	struct file *file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
  	char name[13];
ca16d140a   KOSAKI Motohiro   mm: don't access ...
521
  	vm_flags_t acctflag = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522

4e9823111   Kirill Korotaev   [PATCH] IPC names...
523
  	if (size < SHMMIN || size > ns->shm_ctlmax)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
  		return -EINVAL;
1376327ce   Manfred Spraul   ipc/shm.c: check ...
525
526
  	if (numpages << PAGE_SHIFT < size)
  		return -ENOSPC;
09c6eb1f6   Manfred Spraul   ipc/shm.c: check ...
527
528
  	if (ns->shm_tot + numpages < ns->shm_tot ||
  			ns->shm_tot + numpages > ns->shm_ctlall)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
  		return -ENOSPC;
42e618f77   Kees Cook   ipc/shm: remove s...
530
531
  	shp = kvmalloc(sizeof(*shp), GFP_KERNEL);
  	if (unlikely(!shp))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
534
  		return -ENOMEM;
  
  	shp->shm_perm.key = key;
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
535
  	shp->shm_perm.mode = (shmflg & S_IRWXUGO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
537
538
539
540
  	shp->mlock_user = NULL;
  
  	shp->shm_perm.security = NULL;
  	error = security_shm_alloc(shp);
  	if (error) {
42e618f77   Kees Cook   ipc/shm: remove s...
541
  		kvfree(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
  		return error;
  	}
239521f31   Manfred Spraul   ipc: whitespace c...
544
  	sprintf(name, "SYSV%08x", key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  	if (shmflg & SHM_HUGETLB) {
c103a4dc4   Andrew Morton   ipc/shmc.c: elimi...
546
  		struct hstate *hs;
091d0d55b   Li Zefan   shm: fix null poi...
547
  		size_t hugesize;
c103a4dc4   Andrew Morton   ipc/shmc.c: elimi...
548
  		hs = hstate_sizelog((shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
091d0d55b   Li Zefan   shm: fix null poi...
549
550
551
552
553
  		if (!hs) {
  			error = -EINVAL;
  			goto no_file;
  		}
  		hugesize = ALIGN(size, huge_page_size(hs));
af73e4d95   Naoya Horiguchi   hugetlbfs: fix mm...
554

5a6fe1259   Mel Gorman   Do not account fo...
555
556
557
  		/* hugetlb_file_setup applies strict accounting */
  		if (shmflg & SHM_NORESERVE)
  			acctflag = VM_NORESERVE;
af73e4d95   Naoya Horiguchi   hugetlbfs: fix mm...
558
  		file = hugetlb_file_setup(name, hugesize, acctflag,
42d7395fe   Andi Kleen   mm: support more ...
559
560
  				  &shp->mlock_user, HUGETLB_SHMFS_INODE,
  				(shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  	} else {
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
562
563
  		/*
  		 * Do not allow no accounting for OVERCOMMIT_NEVER, even
239521f31   Manfred Spraul   ipc: whitespace c...
564
  		 * if it's asked for.
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
565
566
567
  		 */
  		if  ((shmflg & SHM_NORESERVE) &&
  				sysctl_overcommit_memory != OVERCOMMIT_NEVER)
fc8744adc   Linus Torvalds   Stop playing sill...
568
  			acctflag = VM_NORESERVE;
e1832f292   Stephen Smalley   ipc: use private ...
569
  		file = shmem_kernel_file_setup(name, size, acctflag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
571
572
573
  	}
  	error = PTR_ERR(file);
  	if (IS_ERR(file))
  		goto no_file;
b488893a3   Pavel Emelyanov   pid namespaces: c...
574
  	shp->shm_cprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
  	shp->shm_lprid = 0;
  	shp->shm_atim = shp->shm_dtim = 0;
7ff2819e8   Deepa Dinamani   ipc: shm: Make sh...
577
  	shp->shm_ctim = ktime_get_real_seconds();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
  	shp->shm_segsz = size;
  	shp->shm_nattch = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	shp->shm_file = file;
5774ed014   Vasiliy Kulikov   shm: handle separ...
581
  	shp->shm_creator = current;
b9a532277   Linus Torvalds   Initialize msg/sh...
582

a2642f877   Manfred Spraul   ipc/shm.c: avoid ...
583
584
  	error = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
  	if (error < 0)
b9a532277   Linus Torvalds   Initialize msg/sh...
585
  		goto no_id;
b9a532277   Linus Torvalds   Initialize msg/sh...
586

ab602f799   Jack Miller   shm: make exit_sh...
587
  	list_add(&shp->shm_clist, &current->sysvshm.shm_clist);
dbfcd91f0   Davidlohr Bueso   ipc: move rcu loc...
588

30475cc12   Badari Pulavarty   Restore shmid as ...
589
590
591
592
  	/*
  	 * 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_...
593
  	file_inode(file)->i_ino = shp->shm_perm.id;
551110a94   Krishnakumar R   [PATCH] hugetlb: ...
594

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

cf9d5d78d   Davidlohr Bueso   ipc: close open c...
598
  	ipc_unlock_object(&shp->shm_perm);
dbfcd91f0   Davidlohr Bueso   ipc: move rcu loc...
599
  	rcu_read_unlock();
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
600
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
  
  no_id:
2195d2818   Hugh Dickins   fix undefined ref...
603
  	if (is_file_hugepages(file) && shp->mlock_user)
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
604
  		user_shm_unlock(size, shp->mlock_user);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
  	fput(file);
  no_file:
a2642f877   Manfred Spraul   ipc/shm.c: avoid ...
607
  	call_rcu(&shp->shm_perm.rcu, shm_rcu_free);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
608
609
  	return error;
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
610
  /*
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
611
   * Called with shm_ids.rwsem and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
612
   */
03f02c765   Nadia Derbey   Storing ipcs into...
613
  static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
614
  {
03f02c765   Nadia Derbey   Storing ipcs into...
615
616
617
618
  	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...
619
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
620
  /*
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
621
   * Called with shm_ids.rwsem and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
622
   */
03f02c765   Nadia Derbey   Storing ipcs into...
623
624
  static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
  				struct ipc_params *params)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
625
  {
03f02c765   Nadia Derbey   Storing ipcs into...
626
627
628
629
  	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...
630
631
632
633
  		return -EINVAL;
  
  	return 0;
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
634
  SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
636
  	struct ipc_namespace *ns;
eb66ec44f   Mathias Krause   ipc: constify ipc...
637
638
639
640
641
  	static const struct ipc_ops shm_ops = {
  		.getnew = newseg,
  		.associate = shm_security,
  		.more_checks = shm_more_checks,
  	};
7748dbfaa   Nadia Derbey   ipc: unify the sy...
642
  	struct ipc_params shm_params;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
643
644
  
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645

7748dbfaa   Nadia Derbey   ipc: unify the sy...
646
647
648
  	shm_params.key = key;
  	shm_params.flg = shmflg;
  	shm_params.u.size = size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
649

7748dbfaa   Nadia Derbey   ipc: unify the sy...
650
  	return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
651
652
653
654
  }
  
  static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version)
  {
239521f31   Manfred Spraul   ipc: whitespace c...
655
  	switch (version) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
657
658
659
660
  	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...
661
  		memset(&out, 0, sizeof(out));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
  		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...
677
678
  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
679
  {
239521f31   Manfred Spraul   ipc: whitespace c...
680
  	switch (version) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
  	case IPC_64:
016d7132f   Pierre Peiffer   IPC: get rid of t...
682
  		if (copy_from_user(out, buf, sizeof(*out)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
684
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
689
690
  	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...
691
692
693
  		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
694
695
696
697
698
699
700
701
702
703
  
  		return 0;
  	    }
  	default:
  		return -EINVAL;
  	}
  }
  
  static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version)
  {
239521f31   Manfred Spraul   ipc: whitespace c...
704
  	switch (version) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705
706
707
708
709
  	case IPC_64:
  		return copy_to_user(buf, in, sizeof(*in));
  	case IPC_OLD:
  	    {
  		struct shminfo out;
239521f31   Manfred Spraul   ipc: whitespace c...
710
  		if (in->shmmax > INT_MAX)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
713
714
715
716
717
  			out.shmmax = INT_MAX;
  		else
  			out.shmmax = (int)in->shmmax;
  
  		out.shmmin	= in->shmmin;
  		out.shmmni	= in->shmmni;
  		out.shmseg	= in->shmseg;
46c0a8ca3   Paul McQuade   ipc, kernel: clea...
718
  		out.shmall	= in->shmall;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
719
720
721
722
723
724
725
  
  		return copy_to_user(buf, &out, sizeof(out));
  	    }
  	default:
  		return -EINVAL;
  	}
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
726
  /*
b79521807   Helge Deller   ipc/shm.c: add RS...
727
   * Calculate and add used RSS and swap pages of a shm.
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
728
   * Called with shm_ids.rwsem held as a reader
b79521807   Helge Deller   ipc/shm.c: add RS...
729
730
731
732
733
   */
  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_...
734
  	inode = file_inode(shp->shm_file);
b79521807   Helge Deller   ipc/shm.c: add RS...
735
736
737
738
739
740
741
742
  
  	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);
63980c80e   Shailesh Pandey   ipc/shm.c: coding...
743

4595ef88d   Kirill A. Shutemov   shmem: make shmem...
744
  		spin_lock_irq(&info->lock);
b79521807   Helge Deller   ipc/shm.c: add RS...
745
746
  		*rss_add += inode->i_mapping->nrpages;
  		*swp_add += info->swapped;
4595ef88d   Kirill A. Shutemov   shmem: make shmem...
747
  		spin_unlock_irq(&info->lock);
b79521807   Helge Deller   ipc/shm.c: add RS...
748
749
750
751
752
753
754
  #else
  		*rss_add += inode->i_mapping->nrpages;
  #endif
  	}
  }
  
  /*
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
755
   * Called with shm_ids.rwsem held as a reader
f4566f048   Nadia Derbey   ipc: fix wrong co...
756
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
757
758
  static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
  		unsigned long *swp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
760
761
  	int next_id;
  	int total, in_use;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
764
  
  	*rss = 0;
  	*swp = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
765
766
767
  	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...
768
  		struct kern_ipc_perm *ipc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
769
  		struct shmid_kernel *shp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770

e562aebc6   Tony Battersby   ipc: make shm_get...
771
772
  		ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
  		if (ipc == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  			continue;
e562aebc6   Tony Battersby   ipc: make shm_get...
774
  		shp = container_of(ipc, struct shmid_kernel, shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775

b79521807   Helge Deller   ipc/shm.c: add RS...
776
  		shm_add_rss_swap(shp, rss, swp);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
777
778
  
  		total++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
779
780
  	}
  }
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
781
  /*
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
782
   * This function handles some shmctl commands which require the rwsem
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
783
   * to be held in write mode.
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
784
   * NOTE: no locks must be held, the rwsem is taken inside this function.
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
785
786
   */
  static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
9ba720c18   Al Viro   shmctl: split the...
787
  		       struct shmid64_ds *shmid64)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  {
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
789
  	struct kern_ipc_perm *ipcp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
  	struct shmid_kernel *shp;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
791
  	int err;
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
792
  	down_write(&shm_ids(ns).rwsem);
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
793
  	rcu_read_lock();
79ccf0f8c   Davidlohr Bueso   ipc,shm: shorten ...
794
  	ipcp = ipcctl_pre_down_nolock(ns, &shm_ids(ns), shmid, cmd,
9ba720c18   Al Viro   shmctl: split the...
795
  				      &shmid64->shm_perm, 0);
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
796
797
  	if (IS_ERR(ipcp)) {
  		err = PTR_ERR(ipcp);
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
798
799
  		goto out_unlock1;
  	}
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
800

a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
801
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
802
803
804
  
  	err = security_shm_shmctl(shp, cmd);
  	if (err)
79ccf0f8c   Davidlohr Bueso   ipc,shm: shorten ...
805
  		goto out_unlock1;
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
806

8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
807
808
  	switch (cmd) {
  	case IPC_RMID:
79ccf0f8c   Davidlohr Bueso   ipc,shm: shorten ...
809
  		ipc_lock_object(&shp->shm_perm);
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
810
  		/* do_shm_rmid unlocks the ipc object and rcu */
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
811
812
813
  		do_shm_rmid(ns, ipcp);
  		goto out_up;
  	case IPC_SET:
79ccf0f8c   Davidlohr Bueso   ipc,shm: shorten ...
814
  		ipc_lock_object(&shp->shm_perm);
9ba720c18   Al Viro   shmctl: split the...
815
  		err = ipc_update_perm(&shmid64->shm_perm, ipcp);
1efdb69b0   Eric W. Biederman   userns: Convert i...
816
  		if (err)
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
817
  			goto out_unlock0;
7ff2819e8   Deepa Dinamani   ipc: shm: Make sh...
818
  		shp->shm_ctim = ktime_get_real_seconds();
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
819
820
821
  		break;
  	default:
  		err = -EINVAL;
79ccf0f8c   Davidlohr Bueso   ipc,shm: shorten ...
822
  		goto out_unlock1;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
823
  	}
7b4cc5d84   Davidlohr Bueso   ipc: move locking...
824
825
826
827
828
  
  out_unlock0:
  	ipc_unlock_object(&shp->shm_perm);
  out_unlock1:
  	rcu_read_unlock();
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
829
  out_up:
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
830
  	up_write(&shm_ids(ns).rwsem);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
831
832
  	return err;
  }
9ba720c18   Al Viro   shmctl: split the...
833
834
  static int shmctl_ipc_info(struct ipc_namespace *ns,
  			   struct shminfo64 *shminfo)
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
835
  {
9ba720c18   Al Viro   shmctl: split the...
836
837
838
839
840
841
842
  	int err = security_shm_shmctl(NULL, IPC_INFO);
  	if (!err) {
  		memset(shminfo, 0, sizeof(*shminfo));
  		shminfo->shmmni = shminfo->shmseg = ns->shm_ctlmni;
  		shminfo->shmmax = ns->shm_ctlmax;
  		shminfo->shmall = ns->shm_ctlall;
  		shminfo->shmmin = SHMMIN;
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
843
  		down_read(&shm_ids(ns).rwsem);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
844
  		err = ipc_get_maxid(&shm_ids(ns));
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
845
  		up_read(&shm_ids(ns).rwsem);
239521f31   Manfred Spraul   ipc: whitespace c...
846
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
  			err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
  	}
9ba720c18   Al Viro   shmctl: split the...
849
850
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851

9ba720c18   Al Viro   shmctl: split the...
852
853
854
855
856
857
  static int shmctl_shm_info(struct ipc_namespace *ns,
  			   struct shm_info *shm_info)
  {
  	int err = security_shm_shmctl(NULL, SHM_INFO);
  	if (!err) {
  		memset(shm_info, 0, sizeof(*shm_info));
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
858
  		down_read(&shm_ids(ns).rwsem);
9ba720c18   Al Viro   shmctl: split the...
859
860
861
862
863
  		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;
  		shm_info->swap_attempts = 0;
  		shm_info->swap_successes = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
864
  		err = ipc_get_maxid(&shm_ids(ns));
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
865
  		up_read(&shm_ids(ns).rwsem);
9ba720c18   Al Viro   shmctl: split the...
866
867
  		if (err < 0)
  			err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
  	}
9ba720c18   Al Viro   shmctl: split the...
869
870
  	return err;
  }
c97cb9cca   Davidlohr Bueso   ipc,shm: make shm...
871

9ba720c18   Al Viro   shmctl: split the...
872
873
874
875
876
877
  static int shmctl_stat(struct ipc_namespace *ns, int shmid,
  			int cmd, struct shmid64_ds *tbuf)
  {
  	struct shmid_kernel *shp;
  	int result;
  	int err;
c97cb9cca   Davidlohr Bueso   ipc,shm: make shm...
878

9ba720c18   Al Viro   shmctl: split the...
879
880
881
882
883
884
885
886
887
888
889
890
  	rcu_read_lock();
  	if (cmd == SHM_STAT) {
  		shp = shm_obtain_object(ns, shmid);
  		if (IS_ERR(shp)) {
  			err = PTR_ERR(shp);
  			goto out_unlock;
  		}
  		result = shp->shm_perm.id;
  	} else {
  		shp = shm_obtain_object_check(ns, shmid);
  		if (IS_ERR(shp)) {
  			err = PTR_ERR(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
891
  			goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  		}
9ba720c18   Al Viro   shmctl: split the...
893
894
  		result = 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895

9ba720c18   Al Viro   shmctl: split the...
896
897
898
  	err = -EACCES;
  	if (ipcperms(ns, &shp->shm_perm, S_IRUGO))
  		goto out_unlock;
c97cb9cca   Davidlohr Bueso   ipc,shm: make shm...
899

9ba720c18   Al Viro   shmctl: split the...
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
  	err = security_shm_shmctl(shp, cmd);
  	if (err)
  		goto out_unlock;
  
  	memset(tbuf, 0, sizeof(*tbuf));
  	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;
  	tbuf->shm_nattch = shp->shm_nattch;
  	rcu_read_unlock();
  	return result;
68eccc1dc   Davidlohr Bueso   ipc,shm: introduc...
915
916
  
  out_unlock:
c97cb9cca   Davidlohr Bueso   ipc,shm: make shm...
917
  	rcu_read_unlock();
68eccc1dc   Davidlohr Bueso   ipc,shm: introduc...
918
919
  	return err;
  }
9ba720c18   Al Viro   shmctl: split the...
920
  static int shmctl_do_lock(struct ipc_namespace *ns, int shmid, int cmd)
68eccc1dc   Davidlohr Bueso   ipc,shm: introduc...
921
922
  {
  	struct shmid_kernel *shp;
9ba720c18   Al Viro   shmctl: split the...
923
924
  	struct file *shm_file;
  	int err;
68eccc1dc   Davidlohr Bueso   ipc,shm: introduc...
925

9ba720c18   Al Viro   shmctl: split the...
926
927
928
929
930
  	rcu_read_lock();
  	shp = shm_obtain_object_check(ns, shmid);
  	if (IS_ERR(shp)) {
  		err = PTR_ERR(shp);
  		goto out_unlock1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
931
  	}
c97cb9cca   Davidlohr Bueso   ipc,shm: make shm...
932

9ba720c18   Al Viro   shmctl: split the...
933
934
935
936
  	audit_ipc_obj(&(shp->shm_perm));
  	err = security_shm_shmctl(shp, cmd);
  	if (err)
  		goto out_unlock1;
c97cb9cca   Davidlohr Bueso   ipc,shm: make shm...
937

9ba720c18   Al Viro   shmctl: split the...
938
  	ipc_lock_object(&shp->shm_perm);
c97cb9cca   Davidlohr Bueso   ipc,shm: make shm...
939

9ba720c18   Al Viro   shmctl: split the...
940
941
942
943
  	/* check if shm_destroy() is tearing down shp */
  	if (!ipc_valid_object(&shp->shm_perm)) {
  		err = -EIDRM;
  		goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944
  	}
073115d6b   Steve Grubb   [PATCH] Rework of...
945

9ba720c18   Al Viro   shmctl: split the...
946
947
  	if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
  		kuid_t euid = current_euid();
0f3d2b013   Rafael Aquini   ipc: introduce ip...
948

9ba720c18   Al Viro   shmctl: split the...
949
950
951
  		if (!uid_eq(euid, shp->shm_perm.uid) &&
  		    !uid_eq(euid, shp->shm_perm.cuid)) {
  			err = -EPERM;
0f3d2b013   Rafael Aquini   ipc: introduce ip...
952
953
  			goto out_unlock0;
  		}
9ba720c18   Al Viro   shmctl: split the...
954
955
956
  		if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK)) {
  			err = -EPERM;
  			goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
  		}
68eccc1dc   Davidlohr Bueso   ipc,shm: introduc...
958
  	}
9ba720c18   Al Viro   shmctl: split the...
959
960
961
  	shm_file = shp->shm_file;
  	if (is_file_hugepages(shm_file))
  		goto out_unlock0;
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
962

9ba720c18   Al Viro   shmctl: split the...
963
964
  	if (cmd == SHM_LOCK) {
  		struct user_struct *user = current_user();
63980c80e   Shailesh Pandey   ipc/shm.c: coding...
965

9ba720c18   Al Viro   shmctl: split the...
966
967
968
969
  		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
970
  		}
9ba720c18   Al Viro   shmctl: split the...
971
  		goto out_unlock0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
  	}
9ba720c18   Al Viro   shmctl: split the...
973
974
975
976
977
978
979
980
981
982
983
984
985
  	/* SHM_UNLOCK */
  	if (!(shp->shm_perm.mode & SHM_LOCKED))
  		goto out_unlock0;
  	shmem_lock(shm_file, 0, shp->mlock_user);
  	shp->shm_perm.mode &= ~SHM_LOCKED;
  	shp->mlock_user = NULL;
  	get_file(shm_file);
  	ipc_unlock_object(&shp->shm_perm);
  	rcu_read_unlock();
  	shmem_unlock_mapping(shm_file->f_mapping);
  
  	fput(shm_file);
  	return err;
2caacaa82   Davidlohr Bueso   ipc,shm: shorten ...
986
987
988
  out_unlock0:
  	ipc_unlock_object(&shp->shm_perm);
  out_unlock1:
c97cb9cca   Davidlohr Bueso   ipc,shm: make shm...
989
  	rcu_read_unlock();
68eccc1dc   Davidlohr Bueso   ipc,shm: introduc...
990
991
992
993
994
  	return err;
  }
  
  SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
  {
68eccc1dc   Davidlohr Bueso   ipc,shm: introduc...
995
996
  	int err, version;
  	struct ipc_namespace *ns;
553f770ef   Al Viro   ipc: move compat ...
997
  	struct shmid64_ds sem64;
68eccc1dc   Davidlohr Bueso   ipc,shm: introduc...
998

2caacaa82   Davidlohr Bueso   ipc,shm: shorten ...
999
1000
  	if (cmd < 0 || shmid < 0)
  		return -EINVAL;
68eccc1dc   Davidlohr Bueso   ipc,shm: introduc...
1001
1002
1003
1004
1005
  
  	version = ipc_parse_version(&cmd);
  	ns = current->nsproxy->ipc_ns;
  
  	switch (cmd) {
9ba720c18   Al Viro   shmctl: split the...
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
  	case IPC_INFO: {
  		struct shminfo64 shminfo;
  		err = shmctl_ipc_info(ns, &shminfo);
  		if (err < 0)
  			return err;
  		if (copy_shminfo_to_user(buf, &shminfo, version))
  			err = -EFAULT;
  		return err;
  	}
  	case SHM_INFO: {
  		struct shm_info shm_info;
  		err = shmctl_shm_info(ns, &shm_info);
  		if (err < 0)
  			return err;
  		if (copy_to_user(buf, &shm_info, sizeof(shm_info)))
  			err = -EFAULT;
  		return err;
  	}
68eccc1dc   Davidlohr Bueso   ipc,shm: introduc...
1024
  	case SHM_STAT:
9ba720c18   Al Viro   shmctl: split the...
1025
  	case IPC_STAT: {
553f770ef   Al Viro   ipc: move compat ...
1026
  		err = shmctl_stat(ns, shmid, cmd, &sem64);
9ba720c18   Al Viro   shmctl: split the...
1027
1028
  		if (err < 0)
  			return err;
553f770ef   Al Viro   ipc: move compat ...
1029
  		if (copy_shmid_to_user(buf, &sem64, version))
9ba720c18   Al Viro   shmctl: split the...
1030
1031
1032
  			err = -EFAULT;
  		return err;
  	}
2caacaa82   Davidlohr Bueso   ipc,shm: shorten ...
1033
  	case IPC_SET:
553f770ef   Al Viro   ipc: move compat ...
1034
  		if (copy_shmid_from_user(&sem64, buf, version))
9ba720c18   Al Viro   shmctl: split the...
1035
  			return -EFAULT;
553f770ef   Al Viro   ipc: move compat ...
1036
  		/* fallthru */
9ba720c18   Al Viro   shmctl: split the...
1037
  	case IPC_RMID:
553f770ef   Al Viro   ipc: move compat ...
1038
  		return shmctl_down(ns, shmid, cmd, &sem64);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
1040
  	case SHM_LOCK:
  	case SHM_UNLOCK:
9ba720c18   Al Viro   shmctl: split the...
1041
1042
1043
1044
1045
  		return shmctl_do_lock(ns, shmid, cmd);
  	default:
  		return -EINVAL;
  	}
  }
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
1046

553f770ef   Al Viro   ipc: move compat ...
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
  #ifdef CONFIG_COMPAT
  
  struct compat_shmid_ds {
  	struct compat_ipc_perm shm_perm;
  	int shm_segsz;
  	compat_time_t shm_atime;
  	compat_time_t shm_dtime;
  	compat_time_t shm_ctime;
  	compat_ipc_pid_t shm_cpid;
  	compat_ipc_pid_t shm_lpid;
  	unsigned short shm_nattch;
  	unsigned short shm_unused;
  	compat_uptr_t shm_unused2;
  	compat_uptr_t shm_unused3;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1062

553f770ef   Al Viro   ipc: move compat ...
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
  struct compat_shminfo64 {
  	compat_ulong_t shmmax;
  	compat_ulong_t shmmin;
  	compat_ulong_t shmmni;
  	compat_ulong_t shmseg;
  	compat_ulong_t shmall;
  	compat_ulong_t __unused1;
  	compat_ulong_t __unused2;
  	compat_ulong_t __unused3;
  	compat_ulong_t __unused4;
  };
073115d6b   Steve Grubb   [PATCH] Rework of...
1074

553f770ef   Al Viro   ipc: move compat ...
1075
1076
1077
1078
1079
  struct compat_shm_info {
  	compat_int_t used_ids;
  	compat_ulong_t shm_tot, shm_rss, shm_swp;
  	compat_ulong_t swap_attempts, swap_successes;
  };
0f3d2b013   Rafael Aquini   ipc: introduce ip...
1080

553f770ef   Al Viro   ipc: move compat ...
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
  static int copy_compat_shminfo_to_user(void __user *buf, struct shminfo64 *in,
  					int version)
  {
  	if (in->shmmax > INT_MAX)
  		in->shmmax = INT_MAX;
  	if (version == IPC_64) {
  		struct compat_shminfo64 info;
  		memset(&info, 0, sizeof(info));
  		info.shmmax = in->shmmax;
  		info.shmmin = in->shmmin;
  		info.shmmni = in->shmmni;
  		info.shmseg = in->shmseg;
  		info.shmall = in->shmall;
  		return copy_to_user(buf, &info, sizeof(info));
  	} else {
  		struct shminfo info;
  		memset(&info, 0, sizeof(info));
  		info.shmmax = in->shmmax;
  		info.shmmin = in->shmmin;
  		info.shmmni = in->shmmni;
  		info.shmseg = in->shmseg;
  		info.shmall = in->shmall;
  		return copy_to_user(buf, &info, sizeof(info));
  	}
  }
0f3d2b013   Rafael Aquini   ipc: introduce ip...
1106

553f770ef   Al Viro   ipc: move compat ...
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
  static int put_compat_shm_info(struct shm_info *ip,
  				struct compat_shm_info __user *uip)
  {
  	struct compat_shm_info info;
  
  	memset(&info, 0, sizeof(info));
  	info.used_ids = ip->used_ids;
  	info.shm_tot = ip->shm_tot;
  	info.shm_rss = ip->shm_rss;
  	info.shm_swp = ip->shm_swp;
  	info.swap_attempts = ip->swap_attempts;
  	info.swap_successes = ip->swap_successes;
b776e4b1a   Al Viro   fix a typo in put...
1119
  	return copy_to_user(uip, &info, sizeof(info));
553f770ef   Al Viro   ipc: move compat ...
1120
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1121

553f770ef   Al Viro   ipc: move compat ...
1122
1123
1124
1125
1126
1127
  static int copy_compat_shmid_to_user(void __user *buf, struct shmid64_ds *in,
  					int version)
  {
  	if (version == IPC_64) {
  		struct compat_shmid64_ds v;
  		memset(&v, 0, sizeof(v));
28327fae6   Al Viro   ipc: make use of ...
1128
  		to_compat_ipc64_perm(&v.shm_perm, &in->shm_perm);
553f770ef   Al Viro   ipc: move compat ...
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
  		v.shm_atime = in->shm_atime;
  		v.shm_dtime = in->shm_dtime;
  		v.shm_ctime = in->shm_ctime;
  		v.shm_segsz = in->shm_segsz;
  		v.shm_nattch = in->shm_nattch;
  		v.shm_cpid = in->shm_cpid;
  		v.shm_lpid = in->shm_lpid;
  		return copy_to_user(buf, &v, sizeof(v));
  	} else {
  		struct compat_shmid_ds v;
  		memset(&v, 0, sizeof(v));
28327fae6   Al Viro   ipc: make use of ...
1140
  		to_compat_ipc_perm(&v.shm_perm, &in->shm_perm);
553f770ef   Al Viro   ipc: move compat ...
1141
  		v.shm_perm.key = in->shm_perm.key;
553f770ef   Al Viro   ipc: move compat ...
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
  		v.shm_atime = in->shm_atime;
  		v.shm_dtime = in->shm_dtime;
  		v.shm_ctime = in->shm_ctime;
  		v.shm_segsz = in->shm_segsz;
  		v.shm_nattch = in->shm_nattch;
  		v.shm_cpid = in->shm_cpid;
  		v.shm_lpid = in->shm_lpid;
  		return copy_to_user(buf, &v, sizeof(v));
  	}
  }
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
1152

553f770ef   Al Viro   ipc: move compat ...
1153
1154
1155
1156
1157
1158
  static int copy_compat_shmid_from_user(struct shmid64_ds *out, void __user *buf,
  					int version)
  {
  	memset(out, 0, sizeof(*out));
  	if (version == IPC_64) {
  		struct compat_shmid64_ds *p = buf;
28327fae6   Al Viro   ipc: make use of ...
1159
  		return get_compat_ipc64_perm(&out->shm_perm, &p->shm_perm);
553f770ef   Al Viro   ipc: move compat ...
1160
1161
  	} else {
  		struct compat_shmid_ds *p = buf;
28327fae6   Al Viro   ipc: make use of ...
1162
  		return get_compat_ipc_perm(&out->shm_perm, &p->shm_perm);
553f770ef   Al Viro   ipc: move compat ...
1163
  	}
553f770ef   Al Viro   ipc: move compat ...
1164
  }
63980c80e   Shailesh Pandey   ipc/shm.c: coding...
1165

553f770ef   Al Viro   ipc: move compat ...
1166
1167
1168
1169
1170
1171
  COMPAT_SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, void __user *, uptr)
  {
  	struct ipc_namespace *ns;
  	struct shmid64_ds sem64;
  	int version = compat_ipc_parse_version(&cmd);
  	int err;
85046579b   Hugh Dickins   SHM_UNLOCK: fix l...
1172

553f770ef   Al Viro   ipc: move compat ...
1173
1174
1175
1176
  	ns = current->nsproxy->ipc_ns;
  
  	if (cmd < 0 || shmid < 0)
  		return -EINVAL;
2caacaa82   Davidlohr Bueso   ipc,shm: shorten ...
1177

553f770ef   Al Viro   ipc: move compat ...
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
  	switch (cmd) {
  	case IPC_INFO: {
  		struct shminfo64 shminfo;
  		err = shmctl_ipc_info(ns, &shminfo);
  		if (err < 0)
  			return err;
  		if (copy_compat_shminfo_to_user(uptr, &shminfo, version))
  			err = -EFAULT;
  		return err;
  	}
  	case SHM_INFO: {
  		struct shm_info shm_info;
  		err = shmctl_shm_info(ns, &shm_info);
  		if (err < 0)
  			return err;
  		if (put_compat_shm_info(&shm_info, uptr))
  			err = -EFAULT;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
1195
  		return err;
2caacaa82   Davidlohr Bueso   ipc,shm: shorten ...
1196
  	}
553f770ef   Al Viro   ipc: move compat ...
1197
1198
1199
1200
1201
  	case IPC_STAT:
  	case SHM_STAT:
  		err = shmctl_stat(ns, shmid, cmd, &sem64);
  		if (err < 0)
  			return err;
58aff0af7   Will Deacon   ipc/shm: Fix orde...
1202
  		if (copy_compat_shmid_to_user(uptr, &sem64, version))
553f770ef   Al Viro   ipc: move compat ...
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
  			err = -EFAULT;
  		return err;
  
  	case IPC_SET:
  		if (copy_compat_shmid_from_user(&sem64, uptr, version))
  			return -EFAULT;
  		/* fallthru */
  	case IPC_RMID:
  		return shmctl_down(ns, shmid, cmd, &sem64);
  	case SHM_LOCK:
  	case SHM_UNLOCK:
  		return shmctl_do_lock(ns, shmid, cmd);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1216
  	default:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
1217
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1218
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1219
1220
  	return err;
  }
553f770ef   Al Viro   ipc: move compat ...
1221
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1222
1223
1224
1225
1226
1227
1228
1229
  
  /*
   * 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.
   */
95e91b831   Davidlohr Bueso   ipc/shm: Fix shma...
1230
1231
  long do_shmat(int shmid, char __user *shmaddr, int shmflg,
  	      ulong *raddr, unsigned long shmlba)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1232
1233
  {
  	struct shmid_kernel *shp;
f0cb88026   Davidlohr Bueso   ipc/shm: some shm...
1234
  	unsigned long addr = (unsigned long)shmaddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1235
  	unsigned long size;
239521f31   Manfred Spraul   ipc: whitespace c...
1236
  	struct file *file;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1237
  	int    err;
f0cb88026   Davidlohr Bueso   ipc/shm: some shm...
1238
  	unsigned long flags = MAP_SHARED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1239
  	unsigned long prot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1240
  	int acc_mode;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
1241
  	struct ipc_namespace *ns;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1242
1243
  	struct shm_file_data *sfd;
  	struct path path;
aeb5d7270   Al Viro   [PATCH] introduce...
1244
  	fmode_t f_mode;
41badc15c   Michel Lespinasse   mm: make do_mmap_...
1245
  	unsigned long populate = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1246

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1247
1248
  	err = -EINVAL;
  	if (shmid < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
  		goto out;
f0cb88026   Davidlohr Bueso   ipc/shm: some shm...
1250
1251
  
  	if (addr) {
079a96ae3   Will Deacon   ipc: add COMPAT_S...
1252
  		if (addr & (shmlba - 1)) {
afdc490b3   Davidlohr Bueso   ipc/shm: fix shma...
1253
  			if (shmflg & SHM_RND) {
67dd0bad8   Davidlohr Bueso   Revert "ipc/shm: ...
1254
  				addr &= ~(shmlba - 1);  /* round down */
afdc490b3   Davidlohr Bueso   ipc/shm: fix shma...
1255
1256
1257
1258
1259
1260
1261
1262
1263
  
  				/*
  				 * Ensure that the round-down is non-nil
  				 * when remapping. This can happen for
  				 * cases when addr < shmlba.
  				 */
  				if (!addr && (shmflg & SHM_REMAP))
  					goto out;
  			} else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1264
1265
1266
  #ifndef __ARCH_FORCE_SHMLBA
  				if (addr & ~PAGE_MASK)
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1267
  					goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1268
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1269

f0cb88026   Davidlohr Bueso   ipc/shm: some shm...
1270
1271
1272
  		flags |= MAP_FIXED;
  	} else if ((shmflg & SHM_REMAP))
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1273
1274
1275
  
  	if (shmflg & SHM_RDONLY) {
  		prot = PROT_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1276
  		acc_mode = S_IRUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1277
  		f_mode = FMODE_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1278
1279
  	} else {
  		prot = PROT_READ | PROT_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1280
  		acc_mode = S_IRUGO | S_IWUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1281
  		f_mode = FMODE_READ | FMODE_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
  	}
  	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...
1292
  	ns = current->nsproxy->ipc_ns;
c2c737a04   Davidlohr Bueso   ipc,shm: shorten ...
1293
1294
  	rcu_read_lock();
  	shp = shm_obtain_object_check(ns, shmid);
023a53557   Nadia Derbey   ipc: integrate ip...
1295
1296
  	if (IS_ERR(shp)) {
  		err = PTR_ERR(shp);
c2c737a04   Davidlohr Bueso   ipc,shm: shorten ...
1297
  		goto out_unlock;
023a53557   Nadia Derbey   ipc: integrate ip...
1298
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1299
1300
  
  	err = -EACCES;
b0e77598f   Serge E. Hallyn   userns: user name...
1301
  	if (ipcperms(ns, &shp->shm_perm, acc_mode))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1302
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1303
1304
  
  	err = security_shm_shmat(shp, shmaddr, shmflg);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1305
1306
  	if (err)
  		goto out_unlock;
c2c737a04   Davidlohr Bueso   ipc,shm: shorten ...
1307
  	ipc_lock_object(&shp->shm_perm);
a399b29df   Greg Thelen   ipc,shm: fix shm_...
1308
1309
  
  	/* check if shm_destroy() is tearing down shp */
0f3d2b013   Rafael Aquini   ipc: introduce ip...
1310
  	if (!ipc_valid_object(&shp->shm_perm)) {
a399b29df   Greg Thelen   ipc,shm: fix shm_...
1311
1312
1313
1314
  		ipc_unlock_object(&shp->shm_perm);
  		err = -EIDRM;
  		goto out_unlock;
  	}
2c48b9c45   Al Viro   switch alloc_file...
1315
1316
  	path = shp->shm_file->f_path;
  	path_get(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1317
  	shp->shm_nattch++;
75c3cfa85   David Howells   VFS: assorted wei...
1318
  	size = i_size_read(d_inode(path.dentry));
c2c737a04   Davidlohr Bueso   ipc,shm: shorten ...
1319
1320
  	ipc_unlock_object(&shp->shm_perm);
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1322
1323
  	err = -ENOMEM;
  	sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
f42569b13   Davidlohr Bueso   ipc,shm: cleanup ...
1324
1325
1326
1327
  	if (!sfd) {
  		path_put(&path);
  		goto out_nattch;
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1328

2c48b9c45   Al Viro   switch alloc_file...
1329
1330
  	file = alloc_file(&path, f_mode,
  			  is_file_hugepages(shp->shm_file) ?
c4caa7781   Al Viro   file ->get_unmapp...
1331
1332
  				&shm_file_operations_huge :
  				&shm_file_operations);
39b652527   Anatol Pomozov   fs: Preserve erro...
1333
  	err = PTR_ERR(file);
f42569b13   Davidlohr Bueso   ipc,shm: cleanup ...
1334
1335
1336
1337
1338
  	if (IS_ERR(file)) {
  		kfree(sfd);
  		path_put(&path);
  		goto out_nattch;
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1339

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1340
  	file->private_data = sfd;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1341
  	file->f_mapping = shp->shm_file->f_mapping;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
1342
  	sfd->id = shp->shm_perm.id;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1343
  	sfd->ns = get_ipc_ns(ns);
703eee654   Eric Biggers   ipc/shm: fix use-...
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
  	/*
  	 * We need to take a reference to the real shm file to prevent the
  	 * pointer from becoming stale in cases where the lifetime of the outer
  	 * file extends beyond that of the shm segment.  It's not usually
  	 * possible, but it can happen during remap_file_pages() emulation as
  	 * that unmaps the memory, then does ->mmap() via file reference only.
  	 * We'll deny the ->mmap() if the shm segment was since removed, but to
  	 * detect shm ID reuse we need to compare the file pointers.
  	 */
  	sfd->file = get_file(shp->shm_file);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1354
  	sfd->vm_ops = NULL;
8b3ec6814   Al Viro   take security_mma...
1355
1356
1357
  	err = security_mmap_file(file, prot, flags);
  	if (err)
  		goto out_fput;
91f4f94ea   Michal Hocko   ipc, shm: make sh...
1358
1359
1360
1361
  	if (down_write_killable(&current->mm->mmap_sem)) {
  		err = -EINTR;
  		goto out_fput;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1362
  	if (addr && !(shmflg & SHM_REMAP)) {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1363
  		err = -EINVAL;
247a8ce82   Manfred Spraul   ipc/shm.c: check ...
1364
1365
  		if (addr + size < addr)
  			goto invalid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1366
1367
  		if (find_vma_intersection(current->mm, addr, addr + size))
  			goto invalid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1368
  	}
f42569b13   Davidlohr Bueso   ipc,shm: cleanup ...
1369

897ab3e0c   Mike Rapoport   userfaultfd: non-...
1370
  	addr = do_mmap_pgoff(file, addr, size, prot, flags, 0, &populate, NULL);
bebeb3d68   Michel Lespinasse   mm: introduce mm_...
1371
  	*raddr = addr;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1372
  	err = 0;
bebeb3d68   Michel Lespinasse   mm: introduce mm_...
1373
1374
  	if (IS_ERR_VALUE(addr))
  		err = (long)addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1375
1376
  invalid:
  	up_write(&current->mm->mmap_sem);
bebeb3d68   Michel Lespinasse   mm: introduce mm_...
1377
  	if (populate)
41badc15c   Michel Lespinasse   mm: make do_mmap_...
1378
  		mm_populate(addr, populate);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1379

8b3ec6814   Al Viro   take security_mma...
1380
  out_fput:
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1381
1382
1383
  	fput(file);
  
  out_nattch:
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
1384
  	down_write(&shm_ids(ns).rwsem);
00c2bf85d   Nadia Derbey   ipc: get rid of i...
1385
  	shp = shm_lock(ns, shmid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1386
  	shp->shm_nattch--;
b34a6b1da   Vasiliy Kulikov   ipc: introduce sh...
1387
  	if (shm_may_destroy(ns, shp))
4e9823111   Kirill Korotaev   [PATCH] IPC names...
1388
  		shm_destroy(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1389
1390
  	else
  		shm_unlock(shp);
d9a605e40   Davidlohr Bueso   ipc: rename ids->...
1391
  	up_write(&shm_ids(ns).rwsem);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1392
  	return err;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1393
1394
  
  out_unlock:
c2c737a04   Davidlohr Bueso   ipc,shm: shorten ...
1395
  	rcu_read_unlock();
f42569b13   Davidlohr Bueso   ipc,shm: cleanup ...
1396
1397
  out:
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1398
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
1399
  SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
1400
1401
1402
  {
  	unsigned long ret;
  	long err;
079a96ae3   Will Deacon   ipc: add COMPAT_S...
1403
  	err = do_shmat(shmid, shmaddr, shmflg, &ret, SHMLBA);
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
1404
1405
1406
1407
1408
  	if (err)
  		return err;
  	force_successful_syscall_return();
  	return (long)ret;
  }
a78ee9ed2   Al Viro   shmat(2): move co...
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
  #ifdef CONFIG_COMPAT
  
  #ifndef COMPAT_SHMLBA
  #define COMPAT_SHMLBA	SHMLBA
  #endif
  
  COMPAT_SYSCALL_DEFINE3(shmat, int, shmid, compat_uptr_t, shmaddr, int, shmflg)
  {
  	unsigned long ret;
  	long err;
  
  	err = do_shmat(shmid, compat_ptr(shmaddr), shmflg, &ret, COMPAT_SHMLBA);
  	if (err)
  		return err;
  	force_successful_syscall_return();
  	return (long)ret;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1427
1428
1429
1430
  /*
   * detach and kill segment if marked destroyed.
   * The work is done in shm_close.
   */
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
1431
  SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1432
1433
  {
  	struct mm_struct *mm = current->mm;
586c7e6a2   Mike Frysinger   shm: fix unused w...
1434
  	struct vm_area_struct *vma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1435
  	unsigned long addr = (unsigned long)shmaddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1436
  	int retval = -EINVAL;
586c7e6a2   Mike Frysinger   shm: fix unused w...
1437
1438
  #ifdef CONFIG_MMU
  	loff_t size = 0;
d3c97900b   Dave Hansen   ipc/shm.c: fix ov...
1439
  	struct file *file;
586c7e6a2   Mike Frysinger   shm: fix unused w...
1440
1441
  	struct vm_area_struct *next;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1442

df1e2fb54   Hugh Dickins   [PATCH] shmdt: ch...
1443
1444
  	if (addr & ~PAGE_MASK)
  		return retval;
91f4f94ea   Michal Hocko   ipc, shm: make sh...
1445
1446
  	if (down_write_killable(&mm->mmap_sem))
  		return -EINTR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1447
1448
1449
1450
1451
1452
1453
1454
1455
  
  	/*
  	 * 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
d3c97900b   Dave Hansen   ipc/shm.c: fix ov...
1456
1457
  	 *   are within the initially determined size and that are from the
  	 *   same shm segment from which we determined the size.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
  	 * 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 ...
1470
  #ifdef CONFIG_MMU
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1471
1472
1473
1474
1475
1476
1477
1478
  	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...
1479
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1480
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
d3c97900b   Dave Hansen   ipc/shm.c: fix ov...
1481
1482
1483
1484
1485
1486
1487
  			/*
  			 * Record the file of the shm segment being
  			 * unmapped.  With mremap(), someone could place
  			 * page from another segment but with equal offsets
  			 * in the range we are unmapping.
  			 */
  			file = vma->vm_file;
07a46ed27   Dave Hansen   shmdt: use i_size...
1488
  			size = i_size_read(file_inode(vma->vm_file));
897ab3e0c   Mike Rapoport   userfaultfd: non-...
1489
  			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
  			/*
  			 * 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...
1506
  	 * prevent overflows and make comparisons vs. equal-width types.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
  	 */
8e36709d8   KAMEZAWA Hiroyuki   [PATCH] shmdt can...
1508
  	size = PAGE_ALIGN(size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1509
1510
1511
1512
  	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...
1513
  		if ((vma->vm_ops == &shm_vm_ops) &&
d3c97900b   Dave Hansen   ipc/shm.c: fix ov...
1514
1515
  		    ((vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) &&
  		    (vma->vm_file == file))
897ab3e0c   Mike Rapoport   userfaultfd: non-...
1516
  			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1517
1518
  		vma = next;
  	}
63980c80e   Shailesh Pandey   ipc/shm.c: coding...
1519
  #else	/* CONFIG_MMU */
8feae1311   David Howells   NOMMU: Make VMAs ...
1520
  	/* under NOMMU conditions, the exact address to be destroyed must be
63980c80e   Shailesh Pandey   ipc/shm.c: coding...
1521
1522
  	 * given
  	 */
530fcd16d   Davidlohr Bueso   ipc, shm: guard a...
1523
  	if (vma && vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) {
897ab3e0c   Mike Rapoport   userfaultfd: non-...
1524
  		do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start, NULL);
8feae1311   David Howells   NOMMU: Make VMAs ...
1525
1526
1527
1528
  		retval = 0;
  	}
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1529
1530
1531
1532
1533
  	up_write(&mm->mmap_sem);
  	return retval;
  }
  
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1534
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
  {
1efdb69b0   Eric W. Biederman   userns: Convert i...
1536
  	struct user_namespace *user_ns = seq_user_ns(s);
ade9f91b3   Kees Cook   ipc: add missing ...
1537
1538
  	struct kern_ipc_perm *ipcp = it;
  	struct shmid_kernel *shp;
b79521807   Helge Deller   ipc/shm.c: add RS...
1539
  	unsigned long rss = 0, swp = 0;
ade9f91b3   Kees Cook   ipc: add missing ...
1540
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
b79521807   Helge Deller   ipc/shm.c: add RS...
1541
  	shm_add_rss_swap(shp, &rss, &swp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1542

6c826818f   Paul Menage   /proc/sysvipc/shm...
1543
1544
1545
1546
1547
  #if BITS_PER_LONG <= 32
  #define SIZE_SPEC "%10lu"
  #else
  #define SIZE_SPEC "%21lu"
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1548

7f032d6ef   Joe Perches   ipc: remove use o...
1549
1550
  	seq_printf(s,
  		   "%10d %10d  %4o " SIZE_SPEC " %5u %5u  "
7ff2819e8   Deepa Dinamani   ipc: shm: Make sh...
1551
  		   "%5lu %5u %5u %5u %5u %10llu %10llu %10llu "
7f032d6ef   Joe Perches   ipc: remove use o...
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
  		   SIZE_SPEC " " SIZE_SPEC "
  ",
  		   shp->shm_perm.key,
  		   shp->shm_perm.id,
  		   shp->shm_perm.mode,
  		   shp->shm_segsz,
  		   shp->shm_cprid,
  		   shp->shm_lprid,
  		   shp->shm_nattch,
  		   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),
  		   shp->shm_atim,
  		   shp->shm_dtim,
  		   shp->shm_ctim,
  		   rss * PAGE_SIZE,
  		   swp * PAGE_SIZE);
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1572
1573
  }
  #endif