FreeBSD kernel kern code
sysv_shm.c
Go to the documentation of this file.
1 /* $NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $ */
2 /*-
3  * Copyright (c) 1994 Adam Glass and Charles Hannum. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  * must display the following acknowledgement:
15  * This product includes software developed by Adam Glass and Charles
16  * Hannum.
17  * 4. The names of the authors may not be used to endorse or promote products
18  * derived from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 /*-
32  * Copyright (c) 2003-2005 McAfee, Inc.
33  * All rights reserved.
34  *
35  * This software was developed for the FreeBSD Project in part by McAfee
36  * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
37  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
38  * program.
39  *
40  * Redistribution and use in source and binary forms, with or without
41  * modification, are permitted provided that the following conditions
42  * are met:
43  * 1. Redistributions of source code must retain the above copyright
44  * notice, this list of conditions and the following disclaimer.
45  * 2. Redistributions in binary form must reproduce the above copyright
46  * notice, this list of conditions and the following disclaimer in the
47  * documentation and/or other materials provided with the distribution.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
50  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
53  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59  * SUCH DAMAGE.
60  */
61 
62 #include <sys/cdefs.h>
63 __FBSDID("$BSDSUniX$");
64 
65 #include "opt_compat.h"
66 #include "opt_sysvipc.h"
67 
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/kernel.h>
71 #include <sys/limits.h>
72 #include <sys/lock.h>
73 #include <sys/sysctl.h>
74 #include <sys/shm.h>
75 #include <sys/proc.h>
76 #include <sys/malloc.h>
77 #include <sys/mman.h>
78 #include <sys/module.h>
79 #include <sys/mutex.h>
80 #include <sys/racct.h>
81 #include <sys/resourcevar.h>
82 #include <sys/stat.h>
83 #include <sys/syscall.h>
84 #include <sys/syscallsubr.h>
85 #include <sys/sysent.h>
86 #include <sys/sysproto.h>
87 #include <sys/jail.h>
88 
89 #include <security/mac/mac_framework.h>
90 
91 #include <vm/vm.h>
92 #include <vm/vm_param.h>
93 #include <vm/pmap.h>
94 #include <vm/vm_object.h>
95 #include <vm/vm_map.h>
96 #include <vm/vm_page.h>
97 #include <vm/vm_pager.h>
98 
99 FEATURE(sysv_shm, "System V shared memory segments support");
100 
101 static MALLOC_DEFINE(M_SHM, "shm", "SVID compatible shared memory segments");
102 
103 static int shmget_allocate_segment(struct thread *td,
104  struct shmget_args *uap, int mode);
105 static int shmget_existing(struct thread *td, struct shmget_args *uap,
106  int mode, int segnum);
107 
108 #define SHMSEG_FREE 0x0200
109 #define SHMSEG_REMOVED 0x0400
110 #define SHMSEG_ALLOCATED 0x0800
111 #define SHMSEG_WANTED 0x1000
112 
114 vm_size_t shm_committed;
115 static struct shmid_kernel *shmsegs;
116 
117 struct shmmap_state {
118  vm_offset_t va;
119  int shmid;
120 };
121 
122 static void shm_deallocate_segment(struct shmid_kernel *);
123 static int shm_find_segment_by_key(key_t);
124 static struct shmid_kernel *shm_find_segment_by_shmid(int);
125 static struct shmid_kernel *shm_find_segment_by_shmidx(int);
126 static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *);
127 static void shmrealloc(void);
128 static int shminit(void);
129 static int sysvshm_modload(struct module *, int, void *);
130 static int shmunload(void);
131 static void shmexit_myhook(struct vmspace *vm);
132 static void shmfork_myhook(struct proc *p1, struct proc *p2);
133 static int sysctl_shmsegs(SYSCTL_HANDLER_ARGS);
134 
135 /*
136  * Tuneable values.
137  */
138 #ifndef SHMMAXPGS
139 #define SHMMAXPGS 131072 /* Note: sysv shared memory is swap backed. */
140 #endif
141 #ifndef SHMMAX
142 #define SHMMAX (SHMMAXPGS*PAGE_SIZE)
143 #endif
144 #ifndef SHMMIN
145 #define SHMMIN 1
146 #endif
147 #ifndef SHMMNI
148 #define SHMMNI 192
149 #endif
150 #ifndef SHMSEG
151 #define SHMSEG 128
152 #endif
153 #ifndef SHMALL
154 #define SHMALL (SHMMAXPGS)
155 #endif
156 
157 struct shminfo shminfo = {
158  SHMMAX,
159  SHMMIN,
160  SHMMNI,
161  SHMSEG,
162  SHMALL
163 };
164 
165 static int shm_use_phys;
166 static int shm_allow_removed;
167 
168 SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RW, &shminfo.shmmax, 0,
169  "Maximum shared memory segment size");
170 SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RW, &shminfo.shmmin, 0,
171  "Minimum shared memory segment size");
172 SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RDTUN, &shminfo.shmmni, 0,
173  "Number of shared memory identifiers");
174 SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RDTUN, &shminfo.shmseg, 0,
175  "Number of segments per process");
176 SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RW, &shminfo.shmall, 0,
177  "Maximum number of pages available for shared memory");
178 SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW,
179  &shm_use_phys, 0, "Enable/Disable locking of shared memory pages in core");
180 SYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RW,
181  &shm_allow_removed, 0,
182  "Enable/Disable attachment to attached segments marked for removal");
183 SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLTYPE_OPAQUE | CTLFLAG_RD,
184  NULL, 0, sysctl_shmsegs, "",
185  "Current number of shared memory segments allocated");
186 
187 static int
189  key_t key;
190 {
191  int i;
192 
193  for (i = 0; i < shmalloced; i++)
194  if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) &&
195  shmsegs[i].u.shm_perm.key == key)
196  return (i);
197  return (-1);
198 }
199 
200 static struct shmid_kernel *
202 {
203  int segnum;
204  struct shmid_kernel *shmseg;
205 
206  segnum = IPCID_TO_IX(shmid);
207  if (segnum < 0 || segnum >= shmalloced)
208  return (NULL);
209  shmseg = &shmsegs[segnum];
210  if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
211  (!shm_allow_removed &&
212  (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) ||
213  shmseg->u.shm_perm.seq != IPCID_TO_SEQ(shmid))
214  return (NULL);
215  return (shmseg);
216 }
217 
218 static struct shmid_kernel *
220 {
221  struct shmid_kernel *shmseg;
222 
223  if (segnum < 0 || segnum >= shmalloced)
224  return (NULL);
225  shmseg = &shmsegs[segnum];
226  if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
227  (!shm_allow_removed &&
228  (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0))
229  return (NULL);
230  return (shmseg);
231 }
232 
233 static void
235  struct shmid_kernel *shmseg;
236 {
237  vm_size_t size;
238 
239  GIANT_REQUIRED;
240 
241  vm_object_deallocate(shmseg->object);
242  shmseg->object = NULL;
243  size = round_page(shmseg->u.shm_segsz);
244  shm_committed -= btoc(size);
245  shm_nused--;
246  shmseg->u.shm_perm.mode = SHMSEG_FREE;
247 #ifdef MAC
248  mac_sysvshm_cleanup(shmseg);
249 #endif
250  racct_sub_cred(shmseg->cred, RACCT_NSHM, 1);
251  racct_sub_cred(shmseg->cred, RACCT_SHMSIZE, size);
252  crfree(shmseg->cred);
253  shmseg->cred = NULL;
254 }
255 
256 static int
257 shm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s)
258 {
259  struct shmid_kernel *shmseg;
260  int segnum, result;
261  vm_size_t size;
262 
263  GIANT_REQUIRED;
264 
265  segnum = IPCID_TO_IX(shmmap_s->shmid);
266  shmseg = &shmsegs[segnum];
267  size = round_page(shmseg->u.shm_segsz);
268  result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size);
269  if (result != KERN_SUCCESS)
270  return (EINVAL);
271  shmmap_s->shmid = -1;
272  shmseg->u.shm_dtime = time_second;
273  if ((--shmseg->u.shm_nattch <= 0) &&
274  (shmseg->u.shm_perm.mode & SHMSEG_REMOVED)) {
275  shm_deallocate_segment(shmseg);
276  shm_last_free = segnum;
277  }
278  return (0);
279 }
280 
281 #ifndef _SYS_SYSPROTO_H_
282 struct shmdt_args {
283  const void *shmaddr;
284 };
285 #endif
286 int
287 sys_shmdt(td, uap)
288  struct thread *td;
289  struct shmdt_args *uap;
290 {
291  struct proc *p = td->td_proc;
292  struct shmmap_state *shmmap_s;
293 #ifdef MAC
294  struct shmid_kernel *shmsegptr;
295 #endif
296  int i;
297  int error = 0;
298 
299  if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
300  return (ENOSYS);
301  mtx_lock(&Giant);
302  shmmap_s = p->p_vmspace->vm_shm;
303  if (shmmap_s == NULL) {
304  error = EINVAL;
305  goto done2;
306  }
307  for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
308  if (shmmap_s->shmid != -1 &&
309  shmmap_s->va == (vm_offset_t)uap->shmaddr) {
310  break;
311  }
312  }
313  if (i == shminfo.shmseg) {
314  error = EINVAL;
315  goto done2;
316  }
317 #ifdef MAC
318  shmsegptr = &shmsegs[IPCID_TO_IX(shmmap_s->shmid)];
319  error = mac_sysvshm_check_shmdt(td->td_ucred, shmsegptr);
320  if (error != 0)
321  goto done2;
322 #endif
323  error = shm_delete_mapping(p->p_vmspace, shmmap_s);
324 done2:
325  mtx_unlock(&Giant);
326  return (error);
327 }
328 
329 #ifndef _SYS_SYSPROTO_H_
330 struct shmat_args {
331  int shmid;
332  const void *shmaddr;
333  int shmflg;
334 };
335 #endif
336 int
337 kern_shmat(td, shmid, shmaddr, shmflg)
338  struct thread *td;
339  int shmid;
340  const void *shmaddr;
341  int shmflg;
342 {
343  struct proc *p = td->td_proc;
344  int i, flags;
345  struct shmid_kernel *shmseg;
346  struct shmmap_state *shmmap_s = NULL;
347  vm_offset_t attach_va;
348  vm_prot_t prot;
349  vm_size_t size;
350  int rv;
351  int error = 0;
352 
353  if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
354  return (ENOSYS);
355  mtx_lock(&Giant);
356  shmmap_s = p->p_vmspace->vm_shm;
357  if (shmmap_s == NULL) {
358  shmmap_s = malloc(shminfo.shmseg * sizeof(struct shmmap_state),
359  M_SHM, M_WAITOK);
360 
361  /*
362  * If malloc() above sleeps, the Giant lock is
363  * temporarily dropped, which allows another thread to
364  * allocate shmmap_state and set vm_shm. Recheck
365  * vm_shm and free the new shmmap_state if another one
366  * is already allocated.
367  */
368  if (p->p_vmspace->vm_shm != NULL) {
369  free(shmmap_s, M_SHM);
370  shmmap_s = p->p_vmspace->vm_shm;
371  } else {
372  for (i = 0; i < shminfo.shmseg; i++)
373  shmmap_s[i].shmid = -1;
374  p->p_vmspace->vm_shm = shmmap_s;
375  }
376  }
377  shmseg = shm_find_segment_by_shmid(shmid);
378  if (shmseg == NULL) {
379  error = EINVAL;
380  goto done2;
381  }
382  error = ipcperm(td, &shmseg->u.shm_perm,
383  (shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
384  if (error)
385  goto done2;
386 #ifdef MAC
387  error = mac_sysvshm_check_shmat(td->td_ucred, shmseg, shmflg);
388  if (error != 0)
389  goto done2;
390 #endif
391  for (i = 0; i < shminfo.shmseg; i++) {
392  if (shmmap_s->shmid == -1)
393  break;
394  shmmap_s++;
395  }
396  if (i >= shminfo.shmseg) {
397  error = EMFILE;
398  goto done2;
399  }
400  size = round_page(shmseg->u.shm_segsz);
401  prot = VM_PROT_READ;
402  if ((shmflg & SHM_RDONLY) == 0)
403  prot |= VM_PROT_WRITE;
404  flags = MAP_ANON | MAP_SHARED;
405  if (shmaddr) {
406  flags |= MAP_FIXED;
407  if (shmflg & SHM_RND) {
408  attach_va = (vm_offset_t)shmaddr & ~(SHMLBA-1);
409  } else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0) {
410  attach_va = (vm_offset_t)shmaddr;
411  } else {
412  error = EINVAL;
413  goto done2;
414  }
415  } else {
416  /*
417  * This is just a hint to vm_map_find() about where to
418  * put it.
419  */
420  PROC_LOCK(p);
421  attach_va = round_page((vm_offset_t)p->p_vmspace->vm_daddr +
422  lim_max(p, RLIMIT_DATA));
423  PROC_UNLOCK(p);
424  }
425 
426  vm_object_reference(shmseg->object);
427  rv = vm_map_find(&p->p_vmspace->vm_map, shmseg->object,
428  0, &attach_va, size, (flags & MAP_FIXED) ? VMFS_NO_SPACE :
429  VMFS_OPTIMAL_SPACE, prot, prot, MAP_INHERIT_SHARE);
430  if (rv != KERN_SUCCESS) {
431  vm_object_deallocate(shmseg->object);
432  error = ENOMEM;
433  goto done2;
434  }
435 
436  shmmap_s->va = attach_va;
437  shmmap_s->shmid = shmid;
438  shmseg->u.shm_lpid = p->p_pid;
439  shmseg->u.shm_atime = time_second;
440  shmseg->u.shm_nattch++;
441  td->td_retval[0] = attach_va;
442 done2:
443  mtx_unlock(&Giant);
444  return (error);
445 }
446 
447 int
448 sys_shmat(td, uap)
449  struct thread *td;
450  struct shmat_args *uap;
451 {
452  return kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg);
453 }
454 
455 int
456 kern_shmctl(td, shmid, cmd, buf, bufsz)
457  struct thread *td;
458  int shmid;
459  int cmd;
460  void *buf;
461  size_t *bufsz;
462 {
463  int error = 0;
464  struct shmid_kernel *shmseg;
465 
466  if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
467  return (ENOSYS);
468 
469  mtx_lock(&Giant);
470  switch (cmd) {
471  /*
472  * It is possible that kern_shmctl is being called from the Linux ABI
473  * layer, in which case, we will need to implement IPC_INFO. It should
474  * be noted that other shmctl calls will be funneled through here for
475  * Linix binaries as well.
476  *
477  * NB: The Linux ABI layer will convert this data to structure(s) more
478  * consistent with the Linux ABI.
479  */
480  case IPC_INFO:
481  memcpy(buf, &shminfo, sizeof(shminfo));
482  if (bufsz)
483  *bufsz = sizeof(shminfo);
484  td->td_retval[0] = shmalloced;
485  goto done2;
486  case SHM_INFO: {
487  struct shm_info shm_info;
488  shm_info.used_ids = shm_nused;
489  shm_info.shm_rss = 0; /*XXX where to get from ? */
490  shm_info.shm_tot = 0; /*XXX where to get from ? */
491  shm_info.shm_swp = 0; /*XXX where to get from ? */
492  shm_info.swap_attempts = 0; /*XXX where to get from ? */
493  shm_info.swap_successes = 0; /*XXX where to get from ? */
494  memcpy(buf, &shm_info, sizeof(shm_info));
495  if (bufsz)
496  *bufsz = sizeof(shm_info);
497  td->td_retval[0] = shmalloced;
498  goto done2;
499  }
500  }
501  if (cmd == SHM_STAT)
502  shmseg = shm_find_segment_by_shmidx(shmid);
503  else
504  shmseg = shm_find_segment_by_shmid(shmid);
505  if (shmseg == NULL) {
506  error = EINVAL;
507  goto done2;
508  }
509 #ifdef MAC
510  error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, cmd);
511  if (error != 0)
512  goto done2;
513 #endif
514  switch (cmd) {
515  case SHM_STAT:
516  case IPC_STAT:
517  error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
518  if (error)
519  goto done2;
520  memcpy(buf, &shmseg->u, sizeof(struct shmid_ds));
521  if (bufsz)
522  *bufsz = sizeof(struct shmid_ds);
523  if (cmd == SHM_STAT)
524  td->td_retval[0] = IXSEQ_TO_IPCID(shmid, shmseg->u.shm_perm);
525  break;
526  case IPC_SET: {
527  struct shmid_ds *shmid;
528 
529  shmid = (struct shmid_ds *)buf;
530  error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
531  if (error)
532  goto done2;
533  shmseg->u.shm_perm.uid = shmid->shm_perm.uid;
534  shmseg->u.shm_perm.gid = shmid->shm_perm.gid;
535  shmseg->u.shm_perm.mode =
536  (shmseg->u.shm_perm.mode & ~ACCESSPERMS) |
537  (shmid->shm_perm.mode & ACCESSPERMS);
538  shmseg->u.shm_ctime = time_second;
539  break;
540  }
541  case IPC_RMID:
542  error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
543  if (error)
544  goto done2;
545  shmseg->u.shm_perm.key = IPC_PRIVATE;
546  shmseg->u.shm_perm.mode |= SHMSEG_REMOVED;
547  if (shmseg->u.shm_nattch <= 0) {
548  shm_deallocate_segment(shmseg);
549  shm_last_free = IPCID_TO_IX(shmid);
550  }
551  break;
552 #if 0
553  case SHM_LOCK:
554  case SHM_UNLOCK:
555 #endif
556  default:
557  error = EINVAL;
558  break;
559  }
560 done2:
561  mtx_unlock(&Giant);
562  return (error);
563 }
564 
565 #ifndef _SYS_SYSPROTO_H_
566 struct shmctl_args {
567  int shmid;
568  int cmd;
569  struct shmid_ds *buf;
570 };
571 #endif
572 int
573 sys_shmctl(td, uap)
574  struct thread *td;
575  struct shmctl_args *uap;
576 {
577  int error = 0;
578  struct shmid_ds buf;
579  size_t bufsz;
580 
581  /*
582  * The only reason IPC_INFO, SHM_INFO, SHM_STAT exists is to support
583  * Linux binaries. If we see the call come through the FreeBSD ABI,
584  * return an error back to the user since we do not to support this.
585  */
586  if (uap->cmd == IPC_INFO || uap->cmd == SHM_INFO ||
587  uap->cmd == SHM_STAT)
588  return (EINVAL);
589 
590  /* IPC_SET needs to copyin the buffer before calling kern_shmctl */
591  if (uap->cmd == IPC_SET) {
592  if ((error = copyin(uap->buf, &buf, sizeof(struct shmid_ds))))
593  goto done;
594  }
595 
596  error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz);
597  if (error)
598  goto done;
599 
600  /* Cases in which we need to copyout */
601  switch (uap->cmd) {
602  case IPC_STAT:
603  error = copyout(&buf, uap->buf, bufsz);
604  break;
605  }
606 
607 done:
608  if (error) {
609  /* Invalidate the return value */
610  td->td_retval[0] = -1;
611  }
612  return (error);
613 }
614 
615 
616 static int
617 shmget_existing(td, uap, mode, segnum)
618  struct thread *td;
619  struct shmget_args *uap;
620  int mode;
621  int segnum;
622 {
623  struct shmid_kernel *shmseg;
624  int error;
625 
626  shmseg = &shmsegs[segnum];
627  if (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) {
628  /*
629  * This segment is in the process of being allocated. Wait
630  * until it's done, and look the key up again (in case the
631  * allocation failed or it was freed).
632  */
633  shmseg->u.shm_perm.mode |= SHMSEG_WANTED;
634  error = tsleep(shmseg, PLOCK | PCATCH, "shmget", 0);
635  if (error)
636  return (error);
637  return (EAGAIN);
638  }
639  if ((uap->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL))
640  return (EEXIST);
641 #ifdef MAC
642  error = mac_sysvshm_check_shmget(td->td_ucred, shmseg, uap->shmflg);
643  if (error != 0)
644  return (error);
645 #endif
646  if (uap->size != 0 && uap->size > shmseg->u.shm_segsz)
647  return (EINVAL);
648  td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm);
649  return (0);
650 }
651 
652 static int
654  struct thread *td;
655  struct shmget_args *uap;
656  int mode;
657 {
658  int i, segnum, shmid;
659  size_t size;
660  struct ucred *cred = td->td_ucred;
661  struct shmid_kernel *shmseg;
662  vm_object_t shm_object;
663 
664  GIANT_REQUIRED;
665 
666  if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
667  return (EINVAL);
668  if (shm_nused >= shminfo.shmmni) /* Any shmids left? */
669  return (ENOSPC);
670  size = round_page(uap->size);
671  if (shm_committed + btoc(size) > shminfo.shmall)
672  return (ENOMEM);
673  if (shm_last_free < 0) {
674  shmrealloc(); /* Maybe expand the shmsegs[] array. */
675  for (i = 0; i < shmalloced; i++)
676  if (shmsegs[i].u.shm_perm.mode & SHMSEG_FREE)
677  break;
678  if (i == shmalloced)
679  return (ENOSPC);
680  segnum = i;
681  } else {
682  segnum = shm_last_free;
683  shm_last_free = -1;
684  }
685  shmseg = &shmsegs[segnum];
686 #ifdef RACCT
687  PROC_LOCK(td->td_proc);
688  if (racct_add(td->td_proc, RACCT_NSHM, 1)) {
689  PROC_UNLOCK(td->td_proc);
690  return (ENOSPC);
691  }
692  if (racct_add(td->td_proc, RACCT_SHMSIZE, size)) {
693  racct_sub(td->td_proc, RACCT_NSHM, 1);
694  PROC_UNLOCK(td->td_proc);
695  return (ENOMEM);
696  }
697  PROC_UNLOCK(td->td_proc);
698 #endif
699  /*
700  * In case we sleep in malloc(), mark the segment present but deleted
701  * so that noone else tries to create the same key.
702  */
703  shmseg->u.shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
704  shmseg->u.shm_perm.key = uap->key;
705  shmseg->u.shm_perm.seq = (shmseg->u.shm_perm.seq + 1) & 0x7fff;
706  shmid = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm);
707 
708  /*
709  * We make sure that we have allocated a pager before we need
710  * to.
711  */
712  shm_object = vm_pager_allocate(shm_use_phys ? OBJT_PHYS : OBJT_SWAP,
713  0, size, VM_PROT_DEFAULT, 0, cred);
714  if (shm_object == NULL) {
715 #ifdef RACCT
716  PROC_LOCK(td->td_proc);
717  racct_sub(td->td_proc, RACCT_NSHM, 1);
718  racct_sub(td->td_proc, RACCT_SHMSIZE, size);
719  PROC_UNLOCK(td->td_proc);
720 #endif
721  return (ENOMEM);
722  }
723  VM_OBJECT_LOCK(shm_object);
724  vm_object_clear_flag(shm_object, OBJ_ONEMAPPING);
725  vm_object_set_flag(shm_object, OBJ_NOSPLIT);
726  VM_OBJECT_UNLOCK(shm_object);
727 
728  shmseg->object = shm_object;
729  shmseg->u.shm_perm.cuid = shmseg->u.shm_perm.uid = cred->cr_uid;
730  shmseg->u.shm_perm.cgid = shmseg->u.shm_perm.gid = cred->cr_gid;
731  shmseg->u.shm_perm.mode = (shmseg->u.shm_perm.mode & SHMSEG_WANTED) |
732  (mode & ACCESSPERMS) | SHMSEG_ALLOCATED;
733  shmseg->cred = crhold(cred);
734  shmseg->u.shm_segsz = uap->size;
735  shmseg->u.shm_cpid = td->td_proc->p_pid;
736  shmseg->u.shm_lpid = shmseg->u.shm_nattch = 0;
737  shmseg->u.shm_atime = shmseg->u.shm_dtime = 0;
738 #ifdef MAC
739  mac_sysvshm_create(cred, shmseg);
740 #endif
741  shmseg->u.shm_ctime = time_second;
742  shm_committed += btoc(size);
743  shm_nused++;
744  if (shmseg->u.shm_perm.mode & SHMSEG_WANTED) {
745  /*
746  * Somebody else wanted this key while we were asleep. Wake
747  * them up now.
748  */
749  shmseg->u.shm_perm.mode &= ~SHMSEG_WANTED;
750  wakeup(shmseg);
751  }
752  td->td_retval[0] = shmid;
753  return (0);
754 }
755 
756 #ifndef _SYS_SYSPROTO_H_
757 struct shmget_args {
758  key_t key;
759  size_t size;
760  int shmflg;
761 };
762 #endif
763 int
764 sys_shmget(td, uap)
765  struct thread *td;
766  struct shmget_args *uap;
767 {
768  int segnum, mode;
769  int error;
770 
771  if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
772  return (ENOSYS);
773  mtx_lock(&Giant);
774  mode = uap->shmflg & ACCESSPERMS;
775  if (uap->key != IPC_PRIVATE) {
776  again:
777  segnum = shm_find_segment_by_key(uap->key);
778  if (segnum >= 0) {
779  error = shmget_existing(td, uap, mode, segnum);
780  if (error == EAGAIN)
781  goto again;
782  goto done2;
783  }
784  if ((uap->shmflg & IPC_CREAT) == 0) {
785  error = ENOENT;
786  goto done2;
787  }
788  }
789  error = shmget_allocate_segment(td, uap, mode);
790 done2:
791  mtx_unlock(&Giant);
792  return (error);
793 }
794 
795 static void
797  struct proc *p1, *p2;
798 {
799  struct shmmap_state *shmmap_s;
800  size_t size;
801  int i;
802 
803  mtx_lock(&Giant);
804  size = shminfo.shmseg * sizeof(struct shmmap_state);
805  shmmap_s = malloc(size, M_SHM, M_WAITOK);
806  bcopy(p1->p_vmspace->vm_shm, shmmap_s, size);
807  p2->p_vmspace->vm_shm = shmmap_s;
808  for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
809  if (shmmap_s->shmid != -1)
810  shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++;
811  mtx_unlock(&Giant);
812 }
813 
814 static void
815 shmexit_myhook(struct vmspace *vm)
816 {
817  struct shmmap_state *base, *shm;
818  int i;
819 
820  if ((base = vm->vm_shm) != NULL) {
821  vm->vm_shm = NULL;
822  mtx_lock(&Giant);
823  for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) {
824  if (shm->shmid != -1)
825  shm_delete_mapping(vm, shm);
826  }
827  mtx_unlock(&Giant);
828  free(base, M_SHM);
829  }
830 }
831 
832 static void
834 {
835  int i;
836  struct shmid_kernel *newsegs;
837 
838  if (shmalloced >= shminfo.shmmni)
839  return;
840 
841  newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK);
842  for (i = 0; i < shmalloced; i++)
843  bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
844  for (; i < shminfo.shmmni; i++) {
845  shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
846  shmsegs[i].u.shm_perm.seq = 0;
847 #ifdef MAC
848  mac_sysvshm_init(&shmsegs[i]);
849 #endif
850  }
851  free(shmsegs, M_SHM);
852  shmsegs = newsegs;
853  shmalloced = shminfo.shmmni;
854 }
855 
856 static struct syscall_helper_data shm_syscalls[] = {
857  SYSCALL_INIT_HELPER(shmat),
858  SYSCALL_INIT_HELPER(shmctl),
859  SYSCALL_INIT_HELPER(shmdt),
860  SYSCALL_INIT_HELPER(shmget),
861 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
862  defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
863  SYSCALL_INIT_HELPER_COMPAT(freebsd7_shmctl),
864 #endif
865 #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
866  SYSCALL_INIT_HELPER(shmsys),
867 #endif
868  SYSCALL_INIT_LAST
869 };
870 
871 #ifdef COMPAT_32BIT
872 #include <compat/compat32bit/compat32bit.h>
873 #include <compat/compat32bit/compat32bit_ipc.h>
874 #include <compat/compat32bit/compat32bit_proto.h>
875 #include <compat/compat32bit/compat32bit_signal.h>
876 #include <compat/compat32bit/compat32bit_syscall.h>
877 #include <compat/compat32bit/compat32bit_util.h>
878 
879 static struct syscall_helper_data shm32_syscalls[] = {
880  SYSCALL32_INIT_HELPER_COMPAT(shmat),
881  SYSCALL32_INIT_HELPER_COMPAT(shmdt),
882  SYSCALL32_INIT_HELPER_COMPAT(shmget),
883  SYSCALL32_INIT_HELPER(compat32bit_shmsys),
884  SYSCALL32_INIT_HELPER(compat32bit_shmctl),
885 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
886  defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
887  SYSCALL32_INIT_HELPER(freebsd7_compat32bit_shmctl),
888 #endif
889  SYSCALL_INIT_LAST
890 };
891 #endif
892 
893 static int
895 {
896  int i, error;
897 
898 #ifndef BURN_BRIDGES
899  if (TUNABLE_ULONG_FETCH("kern.ipc.shmmaxpgs", &shminfo.shmall) != 0)
900  printf("kern.ipc.shmmaxpgs is now called kern.ipc.shmall!\n");
901 #endif
902  TUNABLE_ULONG_FETCH("kern.ipc.shmall", &shminfo.shmall);
903 
904  /* Initialize shmmax dealing with possible overflow. */
905  for (i = PAGE_SIZE; i > 0; i--) {
906  shminfo.shmmax = shminfo.shmall * i;
907  if (shminfo.shmmax >= shminfo.shmall)
908  break;
909  }
910 
911  TUNABLE_ULONG_FETCH("kern.ipc.shmmin", &shminfo.shmmin);
912  TUNABLE_ULONG_FETCH("kern.ipc.shmmni", &shminfo.shmmni);
913  TUNABLE_ULONG_FETCH("kern.ipc.shmseg", &shminfo.shmseg);
914  TUNABLE_INT_FETCH("kern.ipc.shm_use_phys", &shm_use_phys);
915 
916  shmalloced = shminfo.shmmni;
917  shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK);
918  for (i = 0; i < shmalloced; i++) {
919  shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
920  shmsegs[i].u.shm_perm.seq = 0;
921 #ifdef MAC
922  mac_sysvshm_init(&shmsegs[i]);
923 #endif
924  }
925  shm_last_free = 0;
926  shm_nused = 0;
927  shm_committed = 0;
930 
932  if (error != 0)
933  return (error);
934 #ifdef COMPAT_32BIT
935  error = syscall32_helper_register(shm32_syscalls);
936  if (error != 0)
937  return (error);
938 #endif
939  return (0);
940 }
941 
942 static int
944 {
945  int i;
946 
947  if (shm_nused > 0)
948  return (EBUSY);
949 
950 #ifdef COMPAT_32BIT
951  syscall32_helper_unregister(shm32_syscalls);
952 #endif
954 
955  for (i = 0; i < shmalloced; i++) {
956 #ifdef MAC
957  mac_sysvshm_destroy(&shmsegs[i]);
958 #endif
959  /*
960  * Objects might be still mapped into the processes
961  * address spaces. Actual free would happen on the
962  * last mapping destruction.
963  */
964  if (shmsegs[i].u.shm_perm.mode != SHMSEG_FREE)
965  vm_object_deallocate(shmsegs[i].object);
966  }
967  free(shmsegs, M_SHM);
968  shmexit_hook = NULL;
969  shmfork_hook = NULL;
970  return (0);
971 }
972 
973 static int
974 sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
975 {
976 
977  return (SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0])));
978 }
979 
980 #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
981 struct oshmid_ds {
982  struct ipc_perm_old shm_perm; /* operation perms */
983  int shm_segsz; /* size of segment (bytes) */
984  u_short shm_cpid; /* pid, creator */
985  u_short shm_lpid; /* pid, last operation */
986  short shm_nattch; /* no. of current attaches */
987  time_t shm_atime; /* last attach time */
988  time_t shm_dtime; /* last detach time */
989  time_t shm_ctime; /* last change time */
990  void *shm_handle; /* internal handle for shm segment */
991 };
992 
993 struct oshmctl_args {
994  int shmid;
995  int cmd;
996  struct oshmid_ds *ubuf;
997 };
998 
999 static int
1000 oshmctl(struct thread *td, struct oshmctl_args *uap)
1001 {
1002 #ifdef COMPAT_43
1003  int error = 0;
1004  struct shmid_kernel *shmseg;
1005  struct oshmid_ds outbuf;
1006 
1007  if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
1008  return (ENOSYS);
1009  mtx_lock(&Giant);
1010  shmseg = shm_find_segment_by_shmid(uap->shmid);
1011  if (shmseg == NULL) {
1012  error = EINVAL;
1013  goto done2;
1014  }
1015  switch (uap->cmd) {
1016  case IPC_STAT:
1017  error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
1018  if (error)
1019  goto done2;
1020 #ifdef MAC
1021  error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, uap->cmd);
1022  if (error != 0)
1023  goto done2;
1024 #endif
1025  ipcperm_new2old(&shmseg->u.shm_perm, &outbuf.shm_perm);
1026  outbuf.shm_segsz = shmseg->u.shm_segsz;
1027  outbuf.shm_cpid = shmseg->u.shm_cpid;
1028  outbuf.shm_lpid = shmseg->u.shm_lpid;
1029  outbuf.shm_nattch = shmseg->u.shm_nattch;
1030  outbuf.shm_atime = shmseg->u.shm_atime;
1031  outbuf.shm_dtime = shmseg->u.shm_dtime;
1032  outbuf.shm_ctime = shmseg->u.shm_ctime;
1033  outbuf.shm_handle = shmseg->object;
1034  error = copyout(&outbuf, uap->ubuf, sizeof(outbuf));
1035  if (error)
1036  goto done2;
1037  break;
1038  default:
1039  error = freebsd7_shmctl(td, (struct freebsd7_shmctl_args *)uap);
1040  break;
1041  }
1042 done2:
1043  mtx_unlock(&Giant);
1044  return (error);
1045 #else
1046  return (EINVAL);
1047 #endif
1048 }
1049 
1050 /* XXX casting to (sy_call_t *) is bogus, as usual. */
1051 static sy_call_t *shmcalls[] = {
1052  (sy_call_t *)sys_shmat, (sy_call_t *)oshmctl,
1053  (sy_call_t *)sys_shmdt, (sy_call_t *)sys_shmget,
1054  (sy_call_t *)freebsd7_shmctl
1055 };
1056 
1057 int
1058 sys_shmsys(td, uap)
1059  struct thread *td;
1060  /* XXX actually varargs. */
1061  struct shmsys_args /* {
1062  int which;
1063  int a2;
1064  int a3;
1065  int a4;
1066  } */ *uap;
1067 {
1068  int error;
1069 
1070  if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
1071  return (ENOSYS);
1072  if (uap->which < 0 ||
1073  uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0]))
1074  return (EINVAL);
1075  mtx_lock(&Giant);
1076  error = (*shmcalls[uap->which])(td, &uap->a2);
1077  mtx_unlock(&Giant);
1078  return (error);
1079 }
1080 
1081 #endif /* i386 && (COMPAT_FREEBSD4 || COMPAT_43) */
1082 
1083 #ifdef COMPAT_32BIT
1084 
1085 int
1086 compat32bit_shmsys(struct thread *td, struct compat32bit_shmsys_args *uap)
1087 {
1088 
1089 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1090  defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1091  switch (uap->which) {
1092  case 0: { /* shmat */
1093  struct shmat_args ap;
1094 
1095  ap.shmid = uap->a2;
1096  ap.shmaddr = PTRIN(uap->a3);
1097  ap.shmflg = uap->a4;
1098  return (sysent[SYS_shmat].sy_call(td, &ap));
1099  }
1100  case 2: { /* shmdt */
1101  struct shmdt_args ap;
1102 
1103  ap.shmaddr = PTRIN(uap->a2);
1104  return (sysent[SYS_shmdt].sy_call(td, &ap));
1105  }
1106  case 3: { /* shmget */
1107  struct shmget_args ap;
1108 
1109  ap.key = uap->a2;
1110  ap.size = uap->a3;
1111  ap.shmflg = uap->a4;
1112  return (sysent[SYS_shmget].sy_call(td, &ap));
1113  }
1114  case 4: { /* shmctl */
1115  struct freebsd7_compat32bit_shmctl_args ap;
1116 
1117  ap.shmid = uap->a2;
1118  ap.cmd = uap->a3;
1119  ap.buf = PTRIN(uap->a4);
1120  return (freebsd7_compat32bit_shmctl(td, &ap));
1121  }
1122  case 1: /* oshmctl */
1123  default:
1124  return (EINVAL);
1125  }
1126 #else
1127  return (nosys(td, NULL));
1128 #endif
1129 }
1130 
1131 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1132  defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1133 int
1134 freebsd7_compat32bit_shmctl(struct thread *td,
1135  struct freebsd7_compat32bit_shmctl_args *uap)
1136 {
1137  int error = 0;
1138  union {
1139  struct shmid_ds shmid_ds;
1140  struct shm_info shm_info;
1141  struct shminfo shminfo;
1142  } u;
1143  union {
1144  struct shmid_ds32_old shmid_ds32;
1145  struct shm_info32 shm_info32;
1146  struct shminfo32 shminfo32;
1147  } u32;
1148  size_t sz;
1149 
1150  if (uap->cmd == IPC_SET) {
1151  if ((error = copyin(uap->buf, &u32.shmid_ds32,
1152  sizeof(u32.shmid_ds32))))
1153  goto done;
1154  compat32bit_ipcperm_old_in(&u32.shmid_ds32.shm_perm,
1155  &u.shmid_ds.shm_perm);
1156  CP(u32.shmid_ds32, u.shmid_ds, shm_segsz);
1157  CP(u32.shmid_ds32, u.shmid_ds, shm_lpid);
1158  CP(u32.shmid_ds32, u.shmid_ds, shm_cpid);
1159  CP(u32.shmid_ds32, u.shmid_ds, shm_nattch);
1160  CP(u32.shmid_ds32, u.shmid_ds, shm_atime);
1161  CP(u32.shmid_ds32, u.shmid_ds, shm_dtime);
1162  CP(u32.shmid_ds32, u.shmid_ds, shm_ctime);
1163  }
1164 
1165  error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz);
1166  if (error)
1167  goto done;
1168 
1169  /* Cases in which we need to copyout */
1170  switch (uap->cmd) {
1171  case IPC_INFO:
1172  CP(u.shminfo, u32.shminfo32, shmmax);
1173  CP(u.shminfo, u32.shminfo32, shmmin);
1174  CP(u.shminfo, u32.shminfo32, shmmni);
1175  CP(u.shminfo, u32.shminfo32, shmseg);
1176  CP(u.shminfo, u32.shminfo32, shmall);
1177  error = copyout(&u32.shminfo32, uap->buf,
1178  sizeof(u32.shminfo32));
1179  break;
1180  case SHM_INFO:
1181  CP(u.shm_info, u32.shm_info32, used_ids);
1182  CP(u.shm_info, u32.shm_info32, shm_rss);
1183  CP(u.shm_info, u32.shm_info32, shm_tot);
1184  CP(u.shm_info, u32.shm_info32, shm_swp);
1185  CP(u.shm_info, u32.shm_info32, swap_attempts);
1186  CP(u.shm_info, u32.shm_info32, swap_successes);
1187  error = copyout(&u32.shm_info32, uap->buf,
1188  sizeof(u32.shm_info32));
1189  break;
1190  case SHM_STAT:
1191  case IPC_STAT:
1192  compat32bit_ipcperm_old_out(&u.shmid_ds.shm_perm,
1193  &u32.shmid_ds32.shm_perm);
1194  if (u.shmid_ds.shm_segsz > INT32_MAX)
1195  u32.shmid_ds32.shm_segsz = INT32_MAX;
1196  else
1197  CP(u.shmid_ds, u32.shmid_ds32, shm_segsz);
1198  CP(u.shmid_ds, u32.shmid_ds32, shm_lpid);
1199  CP(u.shmid_ds, u32.shmid_ds32, shm_cpid);
1200  CP(u.shmid_ds, u32.shmid_ds32, shm_nattch);
1201  CP(u.shmid_ds, u32.shmid_ds32, shm_atime);
1202  CP(u.shmid_ds, u32.shmid_ds32, shm_dtime);
1203  CP(u.shmid_ds, u32.shmid_ds32, shm_ctime);
1204  u32.shmid_ds32.shm_internal = 0;
1205  error = copyout(&u32.shmid_ds32, uap->buf,
1206  sizeof(u32.shmid_ds32));
1207  break;
1208  }
1209 
1210 done:
1211  if (error) {
1212  /* Invalidate the return value */
1213  td->td_retval[0] = -1;
1214  }
1215  return (error);
1216 }
1217 #endif
1218 
1219 int
1220 compat32bit_shmctl(struct thread *td, struct compat32bit_shmctl_args *uap)
1221 {
1222  int error = 0;
1223  union {
1224  struct shmid_ds shmid_ds;
1225  struct shm_info shm_info;
1226  struct shminfo shminfo;
1227  } u;
1228  union {
1229  struct shmid_ds32 shmid_ds32;
1230  struct shm_info32 shm_info32;
1231  struct shminfo32 shminfo32;
1232  } u32;
1233  size_t sz;
1234 
1235  if (uap->cmd == IPC_SET) {
1236  if ((error = copyin(uap->buf, &u32.shmid_ds32,
1237  sizeof(u32.shmid_ds32))))
1238  goto done;
1239  compat32bit_ipcperm_in(&u32.shmid_ds32.shm_perm,
1240  &u.shmid_ds.shm_perm);
1241  CP(u32.shmid_ds32, u.shmid_ds, shm_segsz);
1242  CP(u32.shmid_ds32, u.shmid_ds, shm_lpid);
1243  CP(u32.shmid_ds32, u.shmid_ds, shm_cpid);
1244  CP(u32.shmid_ds32, u.shmid_ds, shm_nattch);
1245  CP(u32.shmid_ds32, u.shmid_ds, shm_atime);
1246  CP(u32.shmid_ds32, u.shmid_ds, shm_dtime);
1247  CP(u32.shmid_ds32, u.shmid_ds, shm_ctime);
1248  }
1249 
1250  error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz);
1251  if (error)
1252  goto done;
1253 
1254  /* Cases in which we need to copyout */
1255  switch (uap->cmd) {
1256  case IPC_INFO:
1257  CP(u.shminfo, u32.shminfo32, shmmax);
1258  CP(u.shminfo, u32.shminfo32, shmmin);
1259  CP(u.shminfo, u32.shminfo32, shmmni);
1260  CP(u.shminfo, u32.shminfo32, shmseg);
1261  CP(u.shminfo, u32.shminfo32, shmall);
1262  error = copyout(&u32.shminfo32, uap->buf,
1263  sizeof(u32.shminfo32));
1264  break;
1265  case SHM_INFO:
1266  CP(u.shm_info, u32.shm_info32, used_ids);
1267  CP(u.shm_info, u32.shm_info32, shm_rss);
1268  CP(u.shm_info, u32.shm_info32, shm_tot);
1269  CP(u.shm_info, u32.shm_info32, shm_swp);
1270  CP(u.shm_info, u32.shm_info32, swap_attempts);
1271  CP(u.shm_info, u32.shm_info32, swap_successes);
1272  error = copyout(&u32.shm_info32, uap->buf,
1273  sizeof(u32.shm_info32));
1274  break;
1275  case SHM_STAT:
1276  case IPC_STAT:
1277  compat32bit_ipcperm_out(&u.shmid_ds.shm_perm,
1278  &u32.shmid_ds32.shm_perm);
1279  if (u.shmid_ds.shm_segsz > INT32_MAX)
1280  u32.shmid_ds32.shm_segsz = INT32_MAX;
1281  else
1282  CP(u.shmid_ds, u32.shmid_ds32, shm_segsz);
1283  CP(u.shmid_ds, u32.shmid_ds32, shm_lpid);
1284  CP(u.shmid_ds, u32.shmid_ds32, shm_cpid);
1285  CP(u.shmid_ds, u32.shmid_ds32, shm_nattch);
1286  CP(u.shmid_ds, u32.shmid_ds32, shm_atime);
1287  CP(u.shmid_ds, u32.shmid_ds32, shm_dtime);
1288  CP(u.shmid_ds, u32.shmid_ds32, shm_ctime);
1289  error = copyout(&u32.shmid_ds32, uap->buf,
1290  sizeof(u32.shmid_ds32));
1291  break;
1292  }
1293 
1294 done:
1295  if (error) {
1296  /* Invalidate the return value */
1297  td->td_retval[0] = -1;
1298  }
1299  return (error);
1300 }
1301 #endif
1302 
1303 #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
1304  defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
1305 
1306 #ifndef CP
1307 #define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0)
1308 #endif
1309 
1310 #ifndef _SYS_SYSPROTO_H_
1311 struct freebsd7_shmctl_args {
1312  int shmid;
1313  int cmd;
1314  struct shmid_ds_old *buf;
1315 };
1316 #endif
1317 int
1318 freebsd7_shmctl(td, uap)
1319  struct thread *td;
1320  struct freebsd7_shmctl_args *uap;
1321 {
1322  int error = 0;
1323  struct shmid_ds_old old;
1324  struct shmid_ds buf;
1325  size_t bufsz;
1326 
1327  /*
1328  * The only reason IPC_INFO, SHM_INFO, SHM_STAT exists is to support
1329  * Linux binaries. If we see the call come through the FreeBSD ABI,
1330  * return an error back to the user since we do not to support this.
1331  */
1332  if (uap->cmd == IPC_INFO || uap->cmd == SHM_INFO ||
1333  uap->cmd == SHM_STAT)
1334  return (EINVAL);
1335 
1336  /* IPC_SET needs to copyin the buffer before calling kern_shmctl */
1337  if (uap->cmd == IPC_SET) {
1338  if ((error = copyin(uap->buf, &old, sizeof(old))))
1339  goto done;
1340  ipcperm_old2new(&old.shm_perm, &buf.shm_perm);
1341  CP(old, buf, shm_segsz);
1342  CP(old, buf, shm_lpid);
1343  CP(old, buf, shm_cpid);
1344  CP(old, buf, shm_nattch);
1345  CP(old, buf, shm_atime);
1346  CP(old, buf, shm_dtime);
1347  CP(old, buf, shm_ctime);
1348  }
1349 
1350  error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz);
1351  if (error)
1352  goto done;
1353 
1354  /* Cases in which we need to copyout */
1355  switch (uap->cmd) {
1356  case IPC_STAT:
1357  ipcperm_new2old(&buf.shm_perm, &old.shm_perm);
1358  if (buf.shm_segsz > INT_MAX)
1359  old.shm_segsz = INT_MAX;
1360  else
1361  CP(buf, old, shm_segsz);
1362  CP(buf, old, shm_lpid);
1363  CP(buf, old, shm_cpid);
1364  if (buf.shm_nattch > SHRT_MAX)
1365  old.shm_nattch = SHRT_MAX;
1366  else
1367  CP(buf, old, shm_nattch);
1368  CP(buf, old, shm_atime);
1369  CP(buf, old, shm_dtime);
1370  CP(buf, old, shm_ctime);
1371  old.shm_internal = NULL;
1372  error = copyout(&old, uap->buf, sizeof(old));
1373  break;
1374  }
1375 
1376 done:
1377  if (error) {
1378  /* Invalidate the return value */
1379  td->td_retval[0] = -1;
1380  }
1381  return (error);
1382 }
1383 
1384 #endif /* COMPAT_FREEBSD4 || COMPAT_FREEBSD5 || COMPAT_FREEBSD6 ||
1385  COMPAT_FREEBSD7 */
1386 
1387 static int
1388 sysvshm_modload(struct module *module, int cmd, void *arg)
1389 {
1390  int error = 0;
1391 
1392  switch (cmd) {
1393  case MOD_LOAD:
1394  error = shminit();
1395  if (error != 0)
1396  shmunload();
1397  break;
1398  case MOD_UNLOAD:
1399  error = shmunload();
1400  break;
1401  case MOD_SHUTDOWN:
1402  break;
1403  default:
1404  error = EINVAL;
1405  break;
1406  }
1407  return (error);
1408 }
1409 
1410 static moduledata_t sysvshm_mod = {
1411  "sysvshm",
1412  &sysvshm_modload,
1413  NULL
1414 };
1415 
1416 DECLARE_MODULE(sysvshm, sysvshm_mod, SI_SUB_SYSV_SHM, SI_ORDER_FIRST);
1417 MODULE_VERSION(sysvshm, 1);
rlim_t lim_max(struct proc *p, int which)
int prison_allow(struct ucred *cred, unsigned flag)
Definition: kern_jail.c:2502
int kern_shmctl(struct thread *td, int shmid, int cmd, void *buf, size_t *bufsz)
Definition: sysv_shm.c:456
int syscall_helper_unregister(struct syscall_helper_data *sd)
int ipcperm(struct thread *td, struct ipc_perm *perm, int acc_mode)
Definition: sysv_ipc.c:86
SYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RW,&shminfo.shmmax, 0,"Maximum shared memory segment size")
volatile time_t time_second
Definition: kern_tc.c:94
#define SHMSEG_WANTED
Definition: sysv_shm.c:111
struct buf * buf
Definition: vfs_bio.c:97
int racct_add(struct proc *p, int resource, uint64_t amount)
Definition: kern_racct.c:1208
static struct shmid_kernel * shm_find_segment_by_shmid(int)
Definition: sysv_shm.c:201
void racct_sub_cred(struct ucred *cred, int resource, uint64_t amount)
Definition: kern_racct.c:1244
const void * shmaddr
Definition: sysv_shm.c:283
int syscall_helper_register(struct syscall_helper_data *sd)
static struct shmid_kernel * shm_find_segment_by_shmidx(int)
Definition: sysv_shm.c:219
static void shm_deallocate_segment(struct shmid_kernel *)
Definition: sysv_shm.c:234
int mode
const void * shmaddr
Definition: sysv_shm.c:332
static int shm_allow_removed
Definition: sysv_shm.c:166
#define SHMSEG
Definition: sysv_shm.c:151
SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW,&shm_use_phys, 0,"Enable/Disable locking of shared memory pages in core")
void * malloc(unsigned long size, struct malloc_type *mtp, int flags)
Definition: kern_malloc.c:454
void(* shmexit_hook)(struct vmspace *)
Definition: sysv_ipc.c:52
static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *)
Definition: sysv_shm.c:257
key_t key
Definition: sysv_shm.c:758
struct sysent sysent[]
Definition: init_sysent.c:36
static int shmget_allocate_segment(struct thread *td, struct shmget_args *uap, int mode)
Definition: sysv_shm.c:653
struct shminfo shminfo
Definition: sysv_shm.c:157
static int shminit(void)
Definition: sysv_shm.c:894
#define SHMSEG_FREE
Definition: sysv_shm.c:108
int nosys(struct thread *td, struct nosys_args *args)
Definition: kern_sig.c:3355
__FBSDID("$BSDSUniX$")
size_t size
Definition: sysv_shm.c:759
#define SHMMNI
Definition: sysv_shm.c:148
static int shm_use_phys
Definition: sysv_shm.c:165
static int shmget_existing(struct thread *td, struct shmget_args *uap, int mode, int segnum)
Definition: sysv_shm.c:617
void racct_sub(struct proc *p, int resource, uint64_t amount)
Definition: kern_racct.c:1239
struct shmid_ds * buf
Definition: sysv_shm.c:569
static void shmrealloc(void)
Definition: sysv_shm.c:833
static struct syscall_helper_data shm_syscalls[]
Definition: sysv_shm.c:856
#define SHMSEG_REMOVED
Definition: sysv_shm.c:109
static void shmexit_myhook(struct vmspace *vm)
Definition: sysv_shm.c:815
struct mtx Giant
Definition: kern_mutex.c:140
static int sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
Definition: sysv_shm.c:974
static int shmalloced
Definition: sysv_shm.c:113
void(* shmfork_hook)(struct proc *, struct proc *)
Definition: sysv_ipc.c:51
DECLARE_MODULE(sysvshm, sysvshm_mod, SI_SUB_SYSV_SHM, SI_ORDER_FIRST)
void crfree(struct ucred *cr)
Definition: kern_prot.c:1835
#define SHMMIN
Definition: sysv_shm.c:145
static int shm_nused
Definition: sysv_shm.c:113
static int shm_last_free
Definition: sysv_shm.c:113
#define SHMSEG_ALLOCATED
Definition: sysv_shm.c:110
int kern_shmat(struct thread *td, int shmid, const void *shmaddr, int shmflg)
Definition: sysv_shm.c:337
SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLTYPE_OPAQUE|CTLFLAG_RD, NULL, 0, sysctl_shmsegs,"","Current number of shared memory segments allocated")
int shmflg
Definition: sysv_shm.c:760
#define SHMALL
Definition: sysv_shm.c:154
struct ucred * crhold(struct ucred *cr)
Definition: kern_prot.c:1824
int sys_shmctl(struct thread *td, struct shmctl_args *uap)
Definition: sysv_shm.c:573
int sys_shmdt(struct thread *td, struct shmdt_args *uap)
Definition: sysv_shm.c:287
void free(void *addr, struct malloc_type *mtp)
Definition: kern_malloc.c:554
int printf(const char *fmt,...)
Definition: subr_prf.c:367
vm_offset_t va
Definition: sysv_shm.c:118
static int sysvshm_modload(struct module *, int, void *)
Definition: sysv_shm.c:1388
linker_file_t * result
Definition: linker_if.m:136
void wakeup(void *ident)
Definition: kern_synch.c:378
int sys_shmget(struct thread *td, struct shmget_args *uap)
Definition: sysv_shm.c:764
int shmflg
Definition: sysv_shm.c:333
MODULE_VERSION(sysvshm, 1)
FEATURE(sysv_shm,"System V shared memory segments support")
static MALLOC_DEFINE(M_SHM,"shm","SVID compatible shared memory segments")
#define SHMMAX
Definition: sysv_shm.c:142
static struct shmid_kernel * shmsegs
Definition: sysv_shm.c:115
static moduledata_t sysvshm_mod
Definition: sysv_shm.c:1410
int sys_shmat(struct thread *td, struct shmat_args *uap)
Definition: sysv_shm.c:448
int shmid
Definition: sysv_shm.c:331
vm_size_t shm_committed
Definition: sysv_shm.c:114
static int shmunload(void)
Definition: sysv_shm.c:943
static int shm_find_segment_by_key(key_t)
Definition: sysv_shm.c:188
static void shmfork_myhook(struct proc *p1, struct proc *p2)
Definition: sysv_shm.c:796