Blame view

ipc/shm.c 26.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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
29
  #include <linux/slab.h>
  #include <linux/mm.h>
  #include <linux/hugetlb.h>
  #include <linux/shm.h>
  #include <linux/init.h>
  #include <linux/file.h>
  #include <linux/mman.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
  #include <linux/shmem_fs.h>
  #include <linux/security.h>
  #include <linux/syscalls.h>
  #include <linux/audit.h>
c59ede7b7   Randy.Dunlap   [PATCH] move capa...
34
  #include <linux/capability.h>
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
35
  #include <linux/ptrace.h>
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
36
  #include <linux/seq_file.h>
3e148c799   Nadia Derbey   fix idr_find() lo...
37
  #include <linux/rwsem.h>
4e9823111   Kirill Korotaev   [PATCH] IPC names...
38
  #include <linux/nsproxy.h>
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
39
  #include <linux/mount.h>
ae5e1b22f   Pavel Emelyanov   namespaces: move ...
40
  #include <linux/ipc_namespace.h>
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
41

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

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

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

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

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
138
139
  /* 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...
140
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
141
142
  	struct file *file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
144
  	shp = shm_lock(sfd->ns, sfd->id);
023a53557   Nadia Derbey   ipc: integrate ip...
145
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  	shp->shm_atim = get_seconds();
b488893a3   Pavel Emelyanov   pid namespaces: c...
147
  	shp->shm_lprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
  	shp->shm_nattch++;
  	shm_unlock(shp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
  /*
   * shm_destroy - free the struct shmid_kernel
   *
f4566f048   Nadia Derbey   ipc: fix wrong co...
154
   * @ns: namespace
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
   * @shp: struct to free
   *
3e148c799   Nadia Derbey   fix idr_find() lo...
157
   * It has to be called with shp and shm_ids.rw_mutex (writer) locked,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
   * but returns with shp unlocked and freed.
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
160
  static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
162
  	ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
163
  	shm_rmid(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
165
166
  	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...
167
  	else if (shp->mlock_user)
6d63079ad   Josef Sipek   [PATCH] struct pa...
168
  		user_shm_unlock(shp->shm_file->f_path.dentry->d_inode->i_size,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
175
  						shp->mlock_user);
  	fput (shp->shm_file);
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  }
  
  /*
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
176
   * remove the attach descriptor vma.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
178
179
180
   * 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...
181
  static void shm_close(struct vm_area_struct *vma)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
183
184
  	struct file * file = vma->vm_file;
  	struct shm_file_data *sfd = shm_file_data(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
  	struct shmid_kernel *shp;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
186
  	struct ipc_namespace *ns = sfd->ns;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
187

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

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
231
232
233
  	return pol;
  }
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
  static int shm_mmap(struct file * file, struct vm_area_struct * vma)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
236
  	struct shm_file_data *sfd = shm_file_data(file);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
237
  	int ret;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
238
239
240
241
  	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...
242
  #ifdef CONFIG_MMU
54cb8821d   Nick Piggin   mm: merge populat...
243
  	BUG_ON(!sfd->vm_ops->fault);
2e92a3bae   David Howells   NOMMU: Fix SYSV I...
244
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
245
246
  	vma->vm_ops = &shm_vm_ops;
  	shm_open(vma);
b0e15190e   David Howells   [PATCH] NOMMU: Ma...
247
248
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
  }
4e9823111   Kirill Korotaev   [PATCH] IPC names...
250
251
  static int shm_release(struct inode *ino, struct file *file)
  {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
252
  	struct shm_file_data *sfd = shm_file_data(file);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
253

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
254
255
256
  	put_ipc_ns(sfd->ns);
  	shm_file_data(file) = NULL;
  	kfree(sfd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
257
258
  	return 0;
  }
7ea808591   Christoph Hellwig   drop unused dentr...
259
  static int shm_fsync(struct file *file, int datasync)
516dffdcd   Adam Litke   [PATCH] Fix get_u...
260
  {
516dffdcd   Adam Litke   [PATCH] Fix get_u...
261
  	struct shm_file_data *sfd = shm_file_data(file);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
262

7ea808591   Christoph Hellwig   drop unused dentr...
263
264
265
  	if (!sfd->file->f_op->fsync)
  		return -EINVAL;
  	return sfd->file->f_op->fsync(sfd->file, datasync);
516dffdcd   Adam Litke   [PATCH] Fix get_u...
266
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
267
268
269
270
271
  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...
272
273
  	return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len,
  						pgoff, flags);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
274
  }
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
275

9a32144e9   Arjan van de Ven   [PATCH] mark stru...
276
  static const struct file_operations shm_file_operations = {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
277
  	.mmap		= shm_mmap,
516dffdcd   Adam Litke   [PATCH] Fix get_u...
278
  	.fsync		= shm_fsync,
4e9823111   Kirill Korotaev   [PATCH] IPC names...
279
  	.release	= shm_release,
ed5e5894b   David Howells   nommu: fix SYSV S...
280
281
282
  #ifndef CONFIG_MMU
  	.get_unmapped_area	= shm_get_unmapped_area,
  #endif
6038f373a   Arnd Bergmann   llseek: automatic...
283
  	.llseek		= noop_llseek,
c4caa7781   Al Viro   file ->get_unmapp...
284
285
286
287
288
289
  };
  
  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...
290
  	.get_unmapped_area	= shm_get_unmapped_area,
6038f373a   Arnd Bergmann   llseek: automatic...
291
  	.llseek		= noop_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
  };
c4caa7781   Al Viro   file ->get_unmapp...
293
294
295
296
  int is_file_shm_hugepages(struct file *file)
  {
  	return file->f_op == &shm_file_operations_huge;
  }
f0f37e2f7   Alexey Dobriyan   const: mark struc...
297
  static const struct vm_operations_struct shm_vm_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
299
  	.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...
300
  	.fault	= shm_fault,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
301
302
303
  #if defined(CONFIG_NUMA)
  	.set_policy = shm_set_policy,
  	.get_policy = shm_get_policy,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
  #endif
  };
f4566f048   Nadia Derbey   ipc: fix wrong co...
306
307
308
309
310
  /**
   * newseg - Create a new shared memory segment
   * @ns: namespace
   * @params: ptr to the structure that contains key, size and shmflg
   *
3e148c799   Nadia Derbey   fix idr_find() lo...
311
   * Called with shm_ids.rw_mutex held as a writer.
f4566f048   Nadia Derbey   ipc: fix wrong co...
312
   */
7748dbfaa   Nadia Derbey   ipc: unify the sy...
313
  static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  {
7748dbfaa   Nadia Derbey   ipc: unify the sy...
315
316
317
  	key_t key = params->key;
  	int shmflg = params->flg;
  	size_t size = params->u.size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
323
  	int error;
  	struct shmid_kernel *shp;
  	int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
  	struct file * file;
  	char name[13];
  	int id;
5a6fe1259   Mel Gorman   Do not account fo...
324
  	int acctflag = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325

4e9823111   Kirill Korotaev   [PATCH] IPC names...
326
  	if (size < SHMMIN || size > ns->shm_ctlmax)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
  		return -EINVAL;
f66d45e99   Guy Streeter   [PATCH] correct s...
328
  	if (ns->shm_tot + numpages > ns->shm_ctlall)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
332
333
334
335
  		return -ENOSPC;
  
  	shp = ipc_rcu_alloc(sizeof(*shp));
  	if (!shp)
  		return -ENOMEM;
  
  	shp->shm_perm.key = key;
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
336
  	shp->shm_perm.mode = (shmflg & S_IRWXUGO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
340
341
342
343
344
  	shp->mlock_user = NULL;
  
  	shp->shm_perm.security = NULL;
  	error = security_shm_alloc(shp);
  	if (error) {
  		ipc_rcu_putref(shp);
  		return error;
  	}
9d66586f7   Eric W. Biederman   shm: fix the file...
345
  	sprintf (name, "SYSV%08x", key);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
346
  	if (shmflg & SHM_HUGETLB) {
5a6fe1259   Mel Gorman   Do not account fo...
347
348
349
  		/* hugetlb_file_setup applies strict accounting */
  		if (shmflg & SHM_NORESERVE)
  			acctflag = VM_NORESERVE;
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
350
  		file = hugetlb_file_setup(name, size, acctflag,
6bfde05bf   Eric B Munson   hugetlbfs: allow ...
351
  					&shp->mlock_user, HUGETLB_SHMFS_INODE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
352
  	} else {
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
353
354
355
356
357
358
  		/*
  		 * 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...
359
  			acctflag = VM_NORESERVE;
bf8f972d3   Badari Pulavarty   [PATCH] SHM_NORES...
360
  		file = shmem_file_setup(name, size, acctflag);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
364
  	}
  	error = PTR_ERR(file);
  	if (IS_ERR(file))
  		goto no_file;
48dea404e   Pierre Peiffer   IPC: use ipc_buil...
365
  	id = ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
283bb7fad   Pierre Peiffer   IPC: fix error ca...
366
367
  	if (id < 0) {
  		error = id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
  		goto no_id;
283bb7fad   Pierre Peiffer   IPC: fix error ca...
369
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370

b488893a3   Pavel Emelyanov   pid namespaces: c...
371
  	shp->shm_cprid = task_tgid_vnr(current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
374
375
376
  	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
377
  	shp->shm_file = file;
30475cc12   Badari Pulavarty   Restore shmid as ...
378
379
380
381
  	/*
  	 * shmid gets reported as "inode#" in /proc/pid/maps.
  	 * proc-ps tools use this. Changing this will break them.
  	 */
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
382
  	file->f_dentry->d_inode->i_ino = shp->shm_perm.id;
551110a94   Krishnakumar R   [PATCH] hugetlb: ...
383

4e9823111   Kirill Korotaev   [PATCH] IPC names...
384
  	ns->shm_tot += numpages;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
385
  	error = shp->shm_perm.id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
386
  	shm_unlock(shp);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
387
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
389
  
  no_id:
2195d2818   Hugh Dickins   fix undefined ref...
390
  	if (is_file_hugepages(file) && shp->mlock_user)
353d5c30c   Hugh Dickins   mm: fix hugetlb b...
391
  		user_shm_unlock(size, shp->mlock_user);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
396
397
  	fput(file);
  no_file:
  	security_shm_free(shp);
  	ipc_rcu_putref(shp);
  	return error;
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
398
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
399
   * Called with shm_ids.rw_mutex and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
400
   */
03f02c765   Nadia Derbey   Storing ipcs into...
401
  static inline int shm_security(struct kern_ipc_perm *ipcp, int shmflg)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
402
  {
03f02c765   Nadia Derbey   Storing ipcs into...
403
404
405
406
  	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...
407
  }
f4566f048   Nadia Derbey   ipc: fix wrong co...
408
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
409
   * Called with shm_ids.rw_mutex and ipcp locked.
f4566f048   Nadia Derbey   ipc: fix wrong co...
410
   */
03f02c765   Nadia Derbey   Storing ipcs into...
411
412
  static inline int shm_more_checks(struct kern_ipc_perm *ipcp,
  				struct ipc_params *params)
7748dbfaa   Nadia Derbey   ipc: unify the sy...
413
  {
03f02c765   Nadia Derbey   Storing ipcs into...
414
415
416
417
  	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...
418
419
420
421
  		return -EINVAL;
  
  	return 0;
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
422
  SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
423
  {
4e9823111   Kirill Korotaev   [PATCH] IPC names...
424
  	struct ipc_namespace *ns;
7748dbfaa   Nadia Derbey   ipc: unify the sy...
425
426
  	struct ipc_ops shm_ops;
  	struct ipc_params shm_params;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
427
428
  
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429

7748dbfaa   Nadia Derbey   ipc: unify the sy...
430
431
432
  	shm_ops.getnew = newseg;
  	shm_ops.associate = shm_security;
  	shm_ops.more_checks = shm_more_checks;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
433

7748dbfaa   Nadia Derbey   ipc: unify the sy...
434
435
436
  	shm_params.key = key;
  	shm_params.flg = shmflg;
  	shm_params.u.size = size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437

7748dbfaa   Nadia Derbey   ipc: unify the sy...
438
  	return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
443
444
445
446
447
448
  }
  
  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...
449
  		memset(&out, 0, sizeof(out));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  		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...
465
466
  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
467
468
469
  {
  	switch(version) {
  	case IPC_64:
016d7132f   Pierre Peiffer   IPC: get rid of t...
470
  		if (copy_from_user(out, buf, sizeof(*out)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
475
476
477
478
  	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...
479
480
481
  		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
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
  
  		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...
515
  /*
b79521807   Helge Deller   ipc/shm.c: add RS...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
   * Calculate and add used RSS and swap pages of a shm.
   * Called with shm_ids.rw_mutex held as a reader
   */
  static void shm_add_rss_swap(struct shmid_kernel *shp,
  	unsigned long *rss_add, unsigned long *swp_add)
  {
  	struct inode *inode;
  
  	inode = shp->shm_file->f_path.dentry->d_inode;
  
  	if (is_file_hugepages(shp->shm_file)) {
  		struct address_space *mapping = inode->i_mapping;
  		struct hstate *h = hstate_file(shp->shm_file);
  		*rss_add += pages_per_huge_page(h) * mapping->nrpages;
  	} else {
  #ifdef CONFIG_SHMEM
  		struct shmem_inode_info *info = SHMEM_I(inode);
  		spin_lock(&info->lock);
  		*rss_add += inode->i_mapping->nrpages;
  		*swp_add += info->swapped;
  		spin_unlock(&info->lock);
  #else
  		*rss_add += inode->i_mapping->nrpages;
  #endif
  	}
  }
  
  /*
3e148c799   Nadia Derbey   fix idr_find() lo...
544
   * Called with shm_ids.rw_mutex held as a reader
f4566f048   Nadia Derbey   ipc: fix wrong co...
545
   */
4e9823111   Kirill Korotaev   [PATCH] IPC names...
546
547
  static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
  		unsigned long *swp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  {
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
549
550
  	int next_id;
  	int total, in_use;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
  
  	*rss = 0;
  	*swp = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
554
555
556
  	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...
557
  		struct kern_ipc_perm *ipc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  		struct shmid_kernel *shp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559

e562aebc6   Tony Battersby   ipc: make shm_get...
560
561
  		ipc = idr_find(&shm_ids(ns).ipcs_idr, next_id);
  		if (ipc == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
  			continue;
e562aebc6   Tony Battersby   ipc: make shm_get...
563
  		shp = container_of(ipc, struct shmid_kernel, shm_perm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564

b79521807   Helge Deller   ipc/shm.c: add RS...
565
  		shm_add_rss_swap(shp, rss, swp);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
566
567
  
  		total++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
568
569
  	}
  }
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
570
571
572
573
574
575
576
  /*
   * This function handles some shmctl commands which require the rw_mutex
   * to be held in write mode.
   * NOTE: no locks must be held, the rw_mutex is taken inside this function.
   */
  static int shmctl_down(struct ipc_namespace *ns, int shmid, int cmd,
  		       struct shmid_ds __user *buf, int version)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
  {
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
578
  	struct kern_ipc_perm *ipcp;
016d7132f   Pierre Peiffer   IPC: get rid of t...
579
  	struct shmid64_ds shmid64;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  	struct shmid_kernel *shp;
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
581
582
583
  	int err;
  
  	if (cmd == IPC_SET) {
016d7132f   Pierre Peiffer   IPC: get rid of t...
584
  		if (copy_shmid_from_user(&shmid64, buf, version))
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
585
586
  			return -EFAULT;
  	}
a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
587
588
589
  	ipcp = ipcctl_pre_down(&shm_ids(ns), shmid, cmd, &shmid64.shm_perm, 0);
  	if (IS_ERR(ipcp))
  		return PTR_ERR(ipcp);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
590

a5f75e7f2   Pierre Peiffer   IPC: consolidate ...
591
  	shp = container_of(ipcp, struct shmid_kernel, shm_perm);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
592
593
594
595
596
597
598
599
600
  
  	err = security_shm_shmctl(shp, cmd);
  	if (err)
  		goto out_unlock;
  	switch (cmd) {
  	case IPC_RMID:
  		do_shm_rmid(ns, ipcp);
  		goto out_up;
  	case IPC_SET:
8f4a3809c   Pierre Peiffer   IPC: introduce ip...
601
  		ipc_update_perm(&shmid64.shm_perm, ipcp);
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
602
603
604
605
606
607
608
609
610
611
612
  		shp->shm_ctim = get_seconds();
  		break;
  	default:
  		err = -EINVAL;
  	}
  out_unlock:
  	shm_unlock(shp);
  out_up:
  	up_write(&shm_ids(ns).rw_mutex);
  	return err;
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
613
  SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
614
615
  {
  	struct shmid_kernel *shp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
616
  	int err, version;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
617
  	struct ipc_namespace *ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
619
620
621
622
623
624
  
  	if (cmd < 0 || shmid < 0) {
  		err = -EINVAL;
  		goto out;
  	}
  
  	version = ipc_parse_version(&cmd);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
625
  	ns = current->nsproxy->ipc_ns;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
627
628
629
630
631
632
633
634
  
  	switch (cmd) { /* replace with proc interface ? */
  	case IPC_INFO:
  	{
  		struct shminfo64 shminfo;
  
  		err = security_shm_shmctl(NULL, cmd);
  		if (err)
  			return err;
e8148f758   WANG Cong   ipc: clean up ipc...
635
  		memset(&shminfo, 0, sizeof(shminfo));
4e9823111   Kirill Korotaev   [PATCH] IPC names...
636
637
638
  		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
639
640
641
642
  
  		shminfo.shmmin = SHMMIN;
  		if(copy_shminfo_to_user (buf, &shminfo, version))
  			return -EFAULT;
f4566f048   Nadia Derbey   ipc: fix wrong co...
643

3e148c799   Nadia Derbey   fix idr_find() lo...
644
  		down_read(&shm_ids(ns).rw_mutex);
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
645
  		err = ipc_get_maxid(&shm_ids(ns));
3e148c799   Nadia Derbey   fix idr_find() lo...
646
  		up_read(&shm_ids(ns).rw_mutex);
f4566f048   Nadia Derbey   ipc: fix wrong co...
647

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
649
650
651
652
653
654
655
656
657
658
  		if(err<0)
  			err = 0;
  		goto out;
  	}
  	case SHM_INFO:
  	{
  		struct shm_info shm_info;
  
  		err = security_shm_shmctl(NULL, cmd);
  		if (err)
  			return err;
e8148f758   WANG Cong   ipc: clean up ipc...
659
  		memset(&shm_info, 0, sizeof(shm_info));
3e148c799   Nadia Derbey   fix idr_find() lo...
660
  		down_read(&shm_ids(ns).rw_mutex);
4e9823111   Kirill Korotaev   [PATCH] IPC names...
661
662
663
  		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
664
665
  		shm_info.swap_attempts = 0;
  		shm_info.swap_successes = 0;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
666
  		err = ipc_get_maxid(&shm_ids(ns));
3e148c799   Nadia Derbey   fix idr_find() lo...
667
  		up_read(&shm_ids(ns).rw_mutex);
e8148f758   WANG Cong   ipc: clean up ipc...
668
  		if (copy_to_user(buf, &shm_info, sizeof(shm_info))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
673
674
675
676
677
678
679
680
  			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...
681

023a53557   Nadia Derbey   ipc: integrate ip...
682
683
684
685
686
687
  		if (cmd == SHM_STAT) {
  			shp = shm_lock(ns, shmid);
  			if (IS_ERR(shp)) {
  				err = PTR_ERR(shp);
  				goto out;
  			}
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
688
  			result = shp->shm_perm.id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
  		} else {
023a53557   Nadia Derbey   ipc: integrate ip...
690
691
692
693
694
  			shp = shm_lock_check(ns, shmid);
  			if (IS_ERR(shp)) {
  				err = PTR_ERR(shp);
  				goto out;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
696
  			result = 0;
  		}
e8148f758   WANG Cong   ipc: clean up ipc...
697
  		err = -EACCES;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
  		if (ipcperms (&shp->shm_perm, S_IRUGO))
  			goto out_unlock;
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock;
023a53557   Nadia Derbey   ipc: integrate ip...
703
  		memset(&tbuf, 0, sizeof(tbuf));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
704
705
706
707
708
709
710
  		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...
711
  		tbuf.shm_nattch	= shp->shm_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
712
713
714
715
716
717
718
719
720
721
  		shm_unlock(shp);
  		if(copy_shmid_to_user (buf, &tbuf, version))
  			err = -EFAULT;
  		else
  			err = result;
  		goto out;
  	}
  	case SHM_LOCK:
  	case SHM_UNLOCK:
  	{
89e004ea5   Lee Schermerhorn   SHM_LOCKED pages ...
722
723
724
  		struct file *uninitialized_var(shm_file);
  
  		lru_add_drain_all();  /* drain pagevecs to lru lists */
023a53557   Nadia Derbey   ipc: integrate ip...
725
726
727
  		shp = shm_lock_check(ns, shmid);
  		if (IS_ERR(shp)) {
  			err = PTR_ERR(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
728
729
  			goto out;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730

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

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
733
  		if (!capable(CAP_IPC_LOCK)) {
414c0708d   David Howells   CRED: Wrap task c...
734
  			uid_t euid = current_euid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
  			err = -EPERM;
414c0708d   David Howells   CRED: Wrap task c...
736
737
  			if (euid != shp->shm_perm.uid &&
  			    euid != shp->shm_perm.cuid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
738
  				goto out_unlock;
f1eb1332b   Jiri Slaby   ipc: use rlimit h...
739
  			if (cmd == SHM_LOCK && !rlimit(RLIMIT_MEMLOCK))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
741
742
743
744
745
746
747
  				goto out_unlock;
  		}
  
  		err = security_shm_shmctl(shp, cmd);
  		if (err)
  			goto out_unlock;
  		
  		if(cmd==SHM_LOCK) {
86a264abe   David Howells   CRED: Wrap curren...
748
  			struct user_struct *user = current_user();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
750
  			if (!is_file_hugepages(shp->shm_file)) {
  				err = shmem_lock(shp->shm_file, 1, user);
7be77e20d   Pavel Emelianov   Fix user struct l...
751
  				if (!err && !(shp->shm_perm.mode & SHM_LOCKED)){
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
752
  					shp->shm_perm.mode |= SHM_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
757
  					shp->mlock_user = user;
  				}
  			}
  		} else if (!is_file_hugepages(shp->shm_file)) {
  			shmem_lock(shp->shm_file, 0, shp->mlock_user);
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
758
  			shp->shm_perm.mode &= ~SHM_LOCKED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
760
761
762
763
764
  			shp->mlock_user = NULL;
  		}
  		shm_unlock(shp);
  		goto out;
  	}
  	case IPC_RMID:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  	case IPC_SET:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
766
767
  		err = shmctl_down(ns, shmid, cmd, buf, version);
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
  	default:
8d4cc8b5c   Pierre Peiffer   IPC/shared memory...
769
  		return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
  out_unlock:
  	shm_unlock(shp);
  out:
  	return err;
  }
  
  /*
   * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
   *
   * NOTE! Despite the name, this is NOT a direct system call entrypoint. The
   * "raddr" thing points to kernel space, and there has to be a wrapper around
   * this.
   */
  long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
  {
  	struct shmid_kernel *shp;
  	unsigned long addr;
  	unsigned long size;
  	struct file * file;
  	int    err;
  	unsigned long flags;
  	unsigned long prot;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
793
  	int acc_mode;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
794
  	unsigned long user_addr;
4e9823111   Kirill Korotaev   [PATCH] IPC names...
795
  	struct ipc_namespace *ns;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
796
797
  	struct shm_file_data *sfd;
  	struct path path;
aeb5d7270   Al Viro   [PATCH] introduce...
798
  	fmode_t f_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799

bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
800
801
  	err = -EINVAL;
  	if (shmid < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  		goto out;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
803
  	else if ((addr = (ulong)shmaddr)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
804
805
806
807
808
809
810
  		if (addr & (SHMLBA-1)) {
  			if (shmflg & SHM_RND)
  				addr &= ~(SHMLBA-1);	   /* round down */
  			else
  #ifndef __ARCH_FORCE_SHMLBA
  				if (addr & ~PAGE_MASK)
  #endif
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
811
  					goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
812
813
814
815
  		}
  		flags = MAP_SHARED | MAP_FIXED;
  	} else {
  		if ((shmflg & SHM_REMAP))
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
816
  			goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
819
820
821
822
  
  		flags = MAP_SHARED;
  	}
  
  	if (shmflg & SHM_RDONLY) {
  		prot = PROT_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
823
  		acc_mode = S_IRUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
824
  		f_mode = FMODE_READ;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
  	} else {
  		prot = PROT_READ | PROT_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  		acc_mode = S_IRUGO | S_IWUGO;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
828
  		f_mode = FMODE_READ | FMODE_WRITE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
832
833
834
835
836
837
838
  	}
  	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...
839
  	ns = current->nsproxy->ipc_ns;
023a53557   Nadia Derbey   ipc: integrate ip...
840
841
842
  	shp = shm_lock_check(ns, shmid);
  	if (IS_ERR(shp)) {
  		err = PTR_ERR(shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
  		goto out;
023a53557   Nadia Derbey   ipc: integrate ip...
844
  	}
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
845
846
847
848
  
  	err = -EACCES;
  	if (ipcperms(&shp->shm_perm, acc_mode))
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
849
850
  
  	err = security_shm_shmat(shp, shmaddr, shmflg);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
851
852
  	if (err)
  		goto out_unlock;
2c48b9c45   Al Viro   switch alloc_file...
853
854
  	path = shp->shm_file->f_path;
  	path_get(&path);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
855
  	shp->shm_nattch++;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
856
  	size = i_size_read(path.dentry->d_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
  	shm_unlock(shp);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
858
859
860
  	err = -ENOMEM;
  	sfd = kzalloc(sizeof(*sfd), GFP_KERNEL);
  	if (!sfd)
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
861
  		goto out_put_dentry;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
862

2c48b9c45   Al Viro   switch alloc_file...
863
864
  	file = alloc_file(&path, f_mode,
  			  is_file_hugepages(shp->shm_file) ?
c4caa7781   Al Viro   file ->get_unmapp...
865
866
  				&shm_file_operations_huge :
  				&shm_file_operations);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
867
868
  	if (!file)
  		goto out_free;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
869
  	file->private_data = sfd;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
870
  	file->f_mapping = shp->shm_file->f_mapping;
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
871
  	sfd->id = shp->shm_perm.id;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
872
873
874
  	sfd->ns = get_ipc_ns(ns);
  	sfd->file = shp->shm_file;
  	sfd->vm_ops = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
875
876
  	down_write(&current->mm->mmap_sem);
  	if (addr && !(shmflg & SHM_REMAP)) {
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
877
  		err = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
879
880
881
882
883
884
885
886
887
888
  		if (find_vma_intersection(current->mm, addr, addr + size))
  			goto invalid;
  		/*
  		 * If shm segment goes below stack, make sure there is some
  		 * space left for the stack to grow (at least 4 pages).
  		 */
  		if (addr < current->mm->start_stack &&
  		    addr > current->mm->start_stack - size - PAGE_SIZE * 5)
  			goto invalid;
  	}
  		
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
889
890
891
892
893
  	user_addr = do_mmap (file, addr, size, prot, flags, 0);
  	*raddr = user_addr;
  	err = 0;
  	if (IS_ERR_VALUE(user_addr))
  		err = (long)user_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
894
895
  invalid:
  	up_write(&current->mm->mmap_sem);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
896
897
898
  	fput(file);
  
  out_nattch:
3e148c799   Nadia Derbey   fix idr_find() lo...
899
  	down_write(&shm_ids(ns).rw_mutex);
00c2bf85d   Nadia Derbey   ipc: get rid of i...
900
  	shp = shm_lock(ns, shmid);
023a53557   Nadia Derbey   ipc: integrate ip...
901
  	BUG_ON(IS_ERR(shp));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
902
903
  	shp->shm_nattch--;
  	if(shp->shm_nattch == 0 &&
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
904
  	   shp->shm_perm.mode & SHM_DEST)
4e9823111   Kirill Korotaev   [PATCH] IPC names...
905
  		shm_destroy(ns, shp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
906
907
  	else
  		shm_unlock(shp);
3e148c799   Nadia Derbey   fix idr_find() lo...
908
  	up_write(&shm_ids(ns).rw_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
911
  out:
  	return err;
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
912
913
914
915
916
917
918
  
  out_unlock:
  	shm_unlock(shp);
  	goto out;
  
  out_free:
  	kfree(sfd);
ce8d2cdf3   Dave Hansen   r/o bind mounts: ...
919
  out_put_dentry:
2c48b9c45   Al Viro   switch alloc_file...
920
  	path_put(&path);
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
921
  	goto out_nattch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
  }
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
923
  SYSCALL_DEFINE3(shmat, int, shmid, char __user *, shmaddr, int, shmflg)
7d87e14c2   Stephen Rothwell   [PATCH] consolida...
924
925
926
927
928
929
930
931
932
933
  {
  	unsigned long ret;
  	long err;
  
  	err = do_shmat(shmid, shmaddr, shmflg, &ret);
  	if (err)
  		return err;
  	force_successful_syscall_return();
  	return (long)ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
935
936
937
  /*
   * detach and kill segment if marked destroyed.
   * The work is done in shm_close.
   */
d5460c997   Heiko Carstens   [CVE-2009-0029] S...
938
  SYSCALL_DEFINE1(shmdt, char __user *, shmaddr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
  {
  	struct mm_struct *mm = current->mm;
586c7e6a2   Mike Frysinger   shm: fix unused w...
941
  	struct vm_area_struct *vma;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
942
  	unsigned long addr = (unsigned long)shmaddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
  	int retval = -EINVAL;
586c7e6a2   Mike Frysinger   shm: fix unused w...
944
945
946
947
  #ifdef CONFIG_MMU
  	loff_t size = 0;
  	struct vm_area_struct *next;
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948

df1e2fb54   Hugh Dickins   [PATCH] shmdt: ch...
949
950
  	if (addr & ~PAGE_MASK)
  		return retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
  	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 ...
974
  #ifdef CONFIG_MMU
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
976
977
978
979
980
981
982
  	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...
983
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
984
  			(vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
6d63079ad   Josef Sipek   [PATCH] struct pa...
985
  			size = vma->vm_file->f_path.dentry->d_inode->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
  			do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
  			/*
  			 * We discovered the size of the shm segment, so
  			 * break out of here and fall through to the next
  			 * loop that uses the size information to stop
  			 * searching for matching vma's.
  			 */
  			retval = 0;
  			vma = next;
  			break;
  		}
  		vma = next;
  	}
  
  	/*
  	 * We need look no further than the maximum address a fragment
  	 * could possibly have landed at. Also cast things to loff_t to
  	 * prevent overflows and make comparisions vs. equal-width types.
  	 */
8e36709d8   KAMEZAWA Hiroyuki   [PATCH] shmdt can...
1005
  	size = PAGE_ALIGN(size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
1007
1008
1009
  	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...
1010
  		if ((vma->vm_ops == &shm_vm_ops) &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1011
1012
1013
1014
1015
  			(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 ...
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
  #else /* CONFIG_MMU */
  	/* under NOMMU conditions, the exact address to be destroyed must be
  	 * given */
  	retval = -EINVAL;
  	if (vma->vm_start == addr && vma->vm_ops == &shm_vm_ops) {
  		do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
  		retval = 0;
  	}
  
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1026
1027
1028
1029
1030
  	up_write(&mm->mmap_sem);
  	return retval;
  }
  
  #ifdef CONFIG_PROC_FS
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1031
  static int sysvipc_shm_proc_show(struct seq_file *s, void *it)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1032
  {
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1033
  	struct shmid_kernel *shp = it;
b79521807   Helge Deller   ipc/shm.c: add RS...
1034
1035
1036
  	unsigned long rss = 0, swp = 0;
  
  	shm_add_rss_swap(shp, &rss, &swp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037

6c826818f   Paul Menage   /proc/sysvipc/shm...
1038
1039
1040
1041
1042
  #if BITS_PER_LONG <= 32
  #define SIZE_SPEC "%10lu"
  #else
  #define SIZE_SPEC "%21lu"
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1043

6c826818f   Paul Menage   /proc/sysvipc/shm...
1044
1045
  	return seq_printf(s,
  			  "%10d %10d  %4o " SIZE_SPEC " %5u %5u  "
b79521807   Helge Deller   ipc/shm.c: add RS...
1046
1047
1048
  			  "%5lu %5u %5u %5u %5u %10lu %10lu %10lu "
  			  SIZE_SPEC " " SIZE_SPEC "
  ",
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1049
  			  shp->shm_perm.key,
7ca7e564e   Nadia Derbey   ipc: store ipcs i...
1050
  			  shp->shm_perm.id,
b33291c0b   Andrew Morton   [PATCH] ipc: expa...
1051
  			  shp->shm_perm.mode,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1052
1053
1054
  			  shp->shm_segsz,
  			  shp->shm_cprid,
  			  shp->shm_lprid,
bc56bba8f   Eric W. Biederman   [PATCH] shm: make...
1055
  			  shp->shm_nattch,
19b4946ca   Mike Waychison   [PATCH] ipc: conv...
1056
1057
1058
1059
1060
1061
  			  shp->shm_perm.uid,
  			  shp->shm_perm.gid,
  			  shp->shm_perm.cuid,
  			  shp->shm_perm.cgid,
  			  shp->shm_atim,
  			  shp->shm_dtim,
b79521807   Helge Deller   ipc/shm.c: add RS...
1062
1063
1064
  			  shp->shm_ctim,
  			  rss * PAGE_SIZE,
  			  swp * PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
1066
  }
  #endif