4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1986, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * University Copyright- Copyright (c) 1982, 1986, 1988
31 * The Regents of the University of California
32 * All Rights Reserved
33 *
34 * University Acknowledgment- Portions of this document are derived from
35 * software developed by the University of California, Berkeley, and its
36 * contributors.
37 */
38
39 /*
40 * Inter-Process Communication Shared Memory Facility.
41 *
42 * See os/ipc.c for a description of common IPC functionality.
43 *
302 }
303 }
304 ANON_LOCK_ENTER(&sp->shm_amp->a_rwlock, RW_WRITER);
305 size = sp->shm_amp->size;
306 ANON_LOCK_EXIT(&sp->shm_amp->a_rwlock);
307
308 /* somewhere to record spt info for final detach */
309 if (sp->shm_sptinfo == NULL)
310 sp->shm_sptinfo = kmem_zalloc(sizeof (sptinfo_t), KM_SLEEP);
311
312 as_rangelock(as);
313
314 if (useISM) {
315 /*
316 * Handle ISM
317 */
318 uint_t share_szc;
319 size_t share_size;
320 struct shm_data ssd;
321 uintptr_t align_hint;
322
323 /*
324 * Pick a share pagesize to use, if (!isspt(sp)).
325 * Otherwise use the already chosen page size.
326 *
327 * For the initial shmat (!isspt(sp)), where sptcreate is
328 * called, map_pgsz is called to recommend a [D]ISM pagesize,
329 * important for systems which offer more than one potential
330 * [D]ISM pagesize.
331 * If the shmat is just to attach to an already created
332 * [D]ISM segment, then use the previously selected page size.
333 */
334 if (!isspt(sp)) {
335 share_size = map_pgsz(MAPPGSZ_ISM, pp, addr, size, 0);
336 if (share_size == 0) {
337 as_rangeunlock(as);
338 error = EINVAL;
339 goto errret;
340 }
341 share_szc = page_szc(share_size);
436 /*
437 * We try to accomodate processors which
438 * may not support execute permissions on
439 * all ISM segments by trying the check
440 * again but without PROT_EXEC.
441 */
442 prot &= ~PROT_EXEC;
443 result = valid_usr_range(base, len, prot, as,
444 as->a_userlimit);
445 }
446 as_purge(as);
447 if (result != RANGE_OKAY ||
448 as_gap(as, len, &base, &len, AH_LO,
449 (caddr_t)NULL) != 0) {
450 error = EINVAL;
451 as_rangeunlock(as);
452 goto errret;
453 }
454 }
455
456 if (!isspt(sp)) {
457 error = sptcreate(size, &segspt, sp->shm_amp, prot,
458 flags, share_szc);
459 if (error) {
460 as_rangeunlock(as);
461 goto errret;
462 }
463 sp->shm_sptinfo->sptas = segspt->s_as;
464 sp->shm_sptseg = segspt;
465 sp->shm_sptprot = prot;
466 } else if ((prot & sp->shm_sptprot) != sp->shm_sptprot) {
467 /*
468 * Ensure we're attaching to an ISM segment with
469 * fewer or equal permissions than what we're
470 * allowed. Fail if the segment has more
471 * permissions than what we're allowed.
472 */
473 error = EACCES;
474 as_rangeunlock(as);
475 goto errret;
476 }
477
478 ssd.shm_sptseg = sp->shm_sptseg;
479 ssd.shm_sptas = sp->shm_sptinfo->sptas;
480 ssd.shm_amp = sp->shm_amp;
481 error = as_map(as, addr, size, segspt_shmattach, &ssd);
482 if (error == 0)
483 sp->shm_ismattch++; /* keep count of ISM attaches */
484 } else {
485
486 /*
731 RW_WRITER);
732 cmn_err(CE_NOTE, "shmctl - couldn't lock %ld"
733 " pages into memory", sp->shm_amp->size);
734 ANON_LOCK_EXIT(&sp->shm_amp->a_rwlock);
735 error = ENOMEM;
736 sp->shm_lkcnt--;
737 }
738 }
739 break;
740
741 /* Unlock segment */
742 case SHM_UNLOCK:
743 if ((error = secpolicy_lock_memory(cr)) != 0)
744 break;
745
746 if (sp->shm_lkcnt && (--sp->shm_lkcnt == 0)) {
747 shmem_unlock(sp, sp->shm_amp);
748 }
749 break;
750
751 default:
752 error = EINVAL;
753 break;
754 }
755 mutex_exit(lock);
756 return (error);
757 }
758
759 static void
760 shm_detach(proc_t *pp, segacct_t *sap)
761 {
762 kshmid_t *sp = sap->sa_id;
763 size_t len = sap->sa_len;
764 caddr_t addr = sap->sa_addr;
765
766 /*
767 * Discard lwpchan mappings.
768 */
769 if (pp->p_lcp != NULL)
770 lwpchan_delete_mapping(pp, addr, addr + len);
771 (void) as_unmap(pp->p_as, addr, len);
772
773 /*
774 * Perform some detach-time accounting.
775 */
776 (void) ipc_lock(shm_svc, sp->shm_perm.ipc_id);
777 if (sap->sa_flags & SHMSA_ISM)
778 sp->shm_ismattch--;
779 sp->shm_dtime = gethrestime_sec();
780 sp->shm_lpid = pp->p_pid;
781 ipc_rele(shm_svc, (kipc_perm_t *)sp); /* Drops lock */
782
783 kmem_free(sap, sizeof (segacct_t));
784 }
785
786 static int
787 shmdt(caddr_t addr)
788 {
789 proc_t *pp = curproc;
790 segacct_t *sap, template;
791
792 mutex_enter(&pp->p_lock);
793 prbarrier(pp); /* block /proc. See shmgetid(). */
794
795 template.sa_addr = addr;
796 template.sa_len = 0;
797 if ((pp->p_segacct == NULL) ||
798 ((sap = avl_find(pp->p_segacct, &template, NULL)) == NULL)) {
799 mutex_exit(&pp->p_lock);
800 return (EINVAL);
|
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1986, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2016 Joyent, Inc.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29
30 /*
31 * University Copyright- Copyright (c) 1982, 1986, 1988
32 * The Regents of the University of California
33 * All Rights Reserved
34 *
35 * University Acknowledgment- Portions of this document are derived from
36 * software developed by the University of California, Berkeley, and its
37 * contributors.
38 */
39
40 /*
41 * Inter-Process Communication Shared Memory Facility.
42 *
43 * See os/ipc.c for a description of common IPC functionality.
44 *
303 }
304 }
305 ANON_LOCK_ENTER(&sp->shm_amp->a_rwlock, RW_WRITER);
306 size = sp->shm_amp->size;
307 ANON_LOCK_EXIT(&sp->shm_amp->a_rwlock);
308
309 /* somewhere to record spt info for final detach */
310 if (sp->shm_sptinfo == NULL)
311 sp->shm_sptinfo = kmem_zalloc(sizeof (sptinfo_t), KM_SLEEP);
312
313 as_rangelock(as);
314
315 if (useISM) {
316 /*
317 * Handle ISM
318 */
319 uint_t share_szc;
320 size_t share_size;
321 struct shm_data ssd;
322 uintptr_t align_hint;
323 long curprot;
324
325 /*
326 * Pick a share pagesize to use, if (!isspt(sp)).
327 * Otherwise use the already chosen page size.
328 *
329 * For the initial shmat (!isspt(sp)), where sptcreate is
330 * called, map_pgsz is called to recommend a [D]ISM pagesize,
331 * important for systems which offer more than one potential
332 * [D]ISM pagesize.
333 * If the shmat is just to attach to an already created
334 * [D]ISM segment, then use the previously selected page size.
335 */
336 if (!isspt(sp)) {
337 share_size = map_pgsz(MAPPGSZ_ISM, pp, addr, size, 0);
338 if (share_size == 0) {
339 as_rangeunlock(as);
340 error = EINVAL;
341 goto errret;
342 }
343 share_szc = page_szc(share_size);
438 /*
439 * We try to accomodate processors which
440 * may not support execute permissions on
441 * all ISM segments by trying the check
442 * again but without PROT_EXEC.
443 */
444 prot &= ~PROT_EXEC;
445 result = valid_usr_range(base, len, prot, as,
446 as->a_userlimit);
447 }
448 as_purge(as);
449 if (result != RANGE_OKAY ||
450 as_gap(as, len, &base, &len, AH_LO,
451 (caddr_t)NULL) != 0) {
452 error = EINVAL;
453 as_rangeunlock(as);
454 goto errret;
455 }
456 }
457
458 curprot = sp->shm_opts & SHM_PROT_MASK;
459 if (!isspt(sp)) {
460 error = sptcreate(size, &segspt, sp->shm_amp, prot,
461 flags, share_szc);
462 if (error) {
463 as_rangeunlock(as);
464 goto errret;
465 }
466 sp->shm_sptinfo->sptas = segspt->s_as;
467 sp->shm_sptseg = segspt;
468 sp->shm_opts = (sp->shm_opts & ~SHM_PROT_MASK) | prot;
469 } else if ((prot & curprot) != curprot) {
470 /*
471 * Ensure we're attaching to an ISM segment with
472 * fewer or equal permissions than what we're
473 * allowed. Fail if the segment has more
474 * permissions than what we're allowed.
475 */
476 error = EACCES;
477 as_rangeunlock(as);
478 goto errret;
479 }
480
481 ssd.shm_sptseg = sp->shm_sptseg;
482 ssd.shm_sptas = sp->shm_sptinfo->sptas;
483 ssd.shm_amp = sp->shm_amp;
484 error = as_map(as, addr, size, segspt_shmattach, &ssd);
485 if (error == 0)
486 sp->shm_ismattch++; /* keep count of ISM attaches */
487 } else {
488
489 /*
734 RW_WRITER);
735 cmn_err(CE_NOTE, "shmctl - couldn't lock %ld"
736 " pages into memory", sp->shm_amp->size);
737 ANON_LOCK_EXIT(&sp->shm_amp->a_rwlock);
738 error = ENOMEM;
739 sp->shm_lkcnt--;
740 }
741 }
742 break;
743
744 /* Unlock segment */
745 case SHM_UNLOCK:
746 if ((error = secpolicy_lock_memory(cr)) != 0)
747 break;
748
749 if (sp->shm_lkcnt && (--sp->shm_lkcnt == 0)) {
750 shmem_unlock(sp, sp->shm_amp);
751 }
752 break;
753
754 /* Stage segment for removal, but don't remove until last detach */
755 case SHM_RMID:
756 if ((error = secpolicy_ipc_owner(cr, (kipc_perm_t *)sp)) != 0)
757 break;
758
759 /*
760 * If attached, just mark it as a pending remove, otherwise
761 * we must perform the normal ipc_rmid now.
762 */
763 if ((sp->shm_perm.ipc_ref - 1) > 0) {
764 sp->shm_opts |= SHM_RM_PENDING;
765 } else {
766 mutex_exit(lock);
767 return (ipc_rmid(shm_svc, shmid, cr));
768 }
769 break;
770
771 default:
772 error = EINVAL;
773 break;
774 }
775 mutex_exit(lock);
776 return (error);
777 }
778
779 static void
780 shm_detach(proc_t *pp, segacct_t *sap)
781 {
782 kshmid_t *sp = sap->sa_id;
783 size_t len = sap->sa_len;
784 caddr_t addr = sap->sa_addr;
785
786 /*
787 * Discard lwpchan mappings.
788 */
789 if (pp->p_lcp != NULL)
790 lwpchan_delete_mapping(pp, addr, addr + len);
791 (void) as_unmap(pp->p_as, addr, len);
792
793 /*
794 * Perform some detach-time accounting.
795 */
796 (void) ipc_lock(shm_svc, sp->shm_perm.ipc_id);
797 if (sap->sa_flags & SHMSA_ISM)
798 sp->shm_ismattch--;
799 sp->shm_dtime = gethrestime_sec();
800 sp->shm_lpid = pp->p_pid;
801 if ((sp->shm_opts & SHM_RM_PENDING) != 0 &&
802 sp->shm_perm.ipc_ref == 2) {
803 /*
804 * If this is the last detach of the segment across the whole
805 * system then now we can perform the delayed IPC_RMID.
806 * The ipc_ref count has 1 for the original 'get' and one for
807 * each 'attach' (see 'stat' handling in shmctl).
808 */
809 sp->shm_opts &= ~SHM_RM_PENDING;
810 mutex_enter(&shm_svc->ipcs_lock);
811 ipc_rmsvc(shm_svc, (kipc_perm_t *)sp); /* Drops lock */
812 ASSERT(!MUTEX_HELD(&shm_svc->ipcs_lock));
813 ASSERT(((kipc_perm_t *)sp)->ipc_ref > 0);
814
815 /* Lock was dropped, need to retake it for following rele. */
816 (void) ipc_lock(shm_svc, sp->shm_perm.ipc_id);
817 }
818 ipc_rele(shm_svc, (kipc_perm_t *)sp); /* Drops lock */
819
820 kmem_free(sap, sizeof (segacct_t));
821 }
822
823 static int
824 shmdt(caddr_t addr)
825 {
826 proc_t *pp = curproc;
827 segacct_t *sap, template;
828
829 mutex_enter(&pp->p_lock);
830 prbarrier(pp); /* block /proc. See shmgetid(). */
831
832 template.sa_addr = addr;
833 template.sa_len = 0;
834 if ((pp->p_segacct == NULL) ||
835 ((sap = avl_find(pp->p_segacct, &template, NULL)) == NULL)) {
836 mutex_exit(&pp->p_lock);
837 return (EINVAL);
|