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);
 
 |