]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/sysv_shm.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / bsd / kern / sysv_shm.c
index 99ad6602e01129735a59ae581f0f715345b1971d..7e778e60d97158e60ad4e25393ec5b2225dded6b 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2019 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -124,7 +124,7 @@ static void shmid_ds_64to32(struct user_shmid_ds *in, struct user32_shmid_ds *ou
 static void shmid_ds_32to64(struct user32_shmid_ds *in, struct user_shmid_ds *out);
 
 /* XXX casting to (sy_call_t *) is bogus, as usual. */
 static void shmid_ds_32to64(struct user32_shmid_ds *in, struct user_shmid_ds *out);
 
 /* XXX casting to (sy_call_t *) is bogus, as usual. */
-static sy_call_t *shmcalls[] = {
+static sy_call_t* const shmcalls[] = {
        (sy_call_t *)shmat, (sy_call_t *)oshmctl,
        (sy_call_t *)shmdt, (sy_call_t *)shmget,
        (sy_call_t *)shmctl
        (sy_call_t *)shmat, (sy_call_t *)oshmctl,
        (sy_call_t *)shmdt, (sy_call_t *)shmget,
        (sy_call_t *)shmctl
@@ -170,11 +170,11 @@ static int shm_delete_mapping(struct proc *, struct shmmap_state *, int);
 #define DEFAULT_SHMALL  1024
 
 struct shminfo shminfo = {
 #define DEFAULT_SHMALL  1024
 
 struct shminfo shminfo = {
-       DEFAULT_SHMMAX,
-       DEFAULT_SHMMIN,
-       DEFAULT_SHMMNI,
-       DEFAULT_SHMSEG,
-       DEFAULT_SHMALL
+       .shmmax = DEFAULT_SHMMAX,
+       .shmmin = DEFAULT_SHMMIN,
+       .shmmni = DEFAULT_SHMMNI,
+       .shmseg = DEFAULT_SHMSEG,
+       .shmall = DEFAULT_SHMALL
 };
 
 #define SHMID_IS_VALID(x) ((x) >= 0)
 };
 
 #define SHMID_IS_VALID(x) ((x) >= 0)
@@ -280,7 +280,8 @@ shm_deallocate_segment(struct shmid_kernel *shmseg)
                FREE(shm_handle, M_SHM);
        }
        shmseg->u.shm_internal = USER_ADDR_NULL;                /* tunnel */
                FREE(shm_handle, M_SHM);
        }
        shmseg->u.shm_internal = USER_ADDR_NULL;                /* tunnel */
-       size = mach_vm_round_page(shmseg->u.shm_segsz);
+       size = vm_map_round_page(shmseg->u.shm_segsz,
+           vm_map_page_mask(current_map()));
        shm_committed -= btoc(size);
        shm_nused--;
        shmseg->u.shm_perm.mode = SHMSEG_FREE;
        shm_committed -= btoc(size);
        shm_nused--;
        shmseg->u.shm_perm.mode = SHMSEG_FREE;
@@ -300,7 +301,8 @@ shm_delete_mapping(__unused struct proc *p, struct shmmap_state *shmmap_s,
 
        segnum = IPCID_TO_IX(shmmap_s->shmid);
        shmseg = &shmsegs[segnum];
 
        segnum = IPCID_TO_IX(shmmap_s->shmid);
        shmseg = &shmsegs[segnum];
-       size = mach_vm_round_page(shmseg->u.shm_segsz); /* XXX done for us? */
+       size = vm_map_round_page(shmseg->u.shm_segsz,
+           vm_map_page_mask(current_map())); /* XXX done for us? */
        if (deallocate) {
                result = mach_vm_deallocate(current_map(), shmmap_s->va, size);
                if (result != KERN_SUCCESS) {
        if (deallocate) {
                result = mach_vm_deallocate(current_map(), shmmap_s->va, size);
                if (result != KERN_SUCCESS) {
@@ -383,6 +385,7 @@ shmat(struct proc *p, struct shmat_args *uap, user_addr_t *retval)
        struct shmmap_state     *shmmap_s = NULL;
        struct shm_handle       *shm_handle;
        mach_vm_address_t       attach_va;      /* attach address in/out */
        struct shmmap_state     *shmmap_s = NULL;
        struct shm_handle       *shm_handle;
        mach_vm_address_t       attach_va;      /* attach address in/out */
+       mach_vm_address_t       shmlba;
        mach_vm_size_t          map_size;       /* size of map entry */
        mach_vm_size_t          mapped_size;
        vm_prot_t           prot;
        mach_vm_size_t          map_size;       /* size of map entry */
        mach_vm_size_t          mapped_size;
        vm_prot_t           prot;
@@ -465,7 +468,8 @@ shmat(struct proc *p, struct shmat_args *uap, user_addr_t *retval)
                goto shmat_out;
        }
 
                goto shmat_out;
        }
 
-       map_size = mach_vm_round_page(shmseg->u.shm_segsz);
+       map_size = vm_map_round_page(shmseg->u.shm_segsz,
+           vm_map_page_mask(current_map()));
        prot = VM_PROT_READ;
        if ((uap->shmflg & SHM_RDONLY) == 0) {
                prot |= VM_PROT_WRITE;
        prot = VM_PROT_READ;
        if ((uap->shmflg & SHM_RDONLY) == 0) {
                prot |= VM_PROT_WRITE;
@@ -476,9 +480,10 @@ shmat(struct proc *p, struct shmat_args *uap, user_addr_t *retval)
        }
 
        attach_va = (mach_vm_address_t)uap->shmaddr;
        }
 
        attach_va = (mach_vm_address_t)uap->shmaddr;
+       shmlba = vm_map_page_size(current_map()); /* XXX instead of SHMLBA */
        if (uap->shmflg & SHM_RND) {
        if (uap->shmflg & SHM_RND) {
-               attach_va &= ~(SHMLBA - 1);
-       } else if ((attach_va & (SHMLBA - 1)) != 0) {
+               attach_va &= ~(shmlba - 1);
+       } else if ((attach_va & (shmlba - 1)) != 0) {
                shmat_ret = EINVAL;
                goto shmat_out;
        }
                shmat_ret = EINVAL;
                goto shmat_out;
        }
@@ -515,10 +520,23 @@ shmat(struct proc *p, struct shmat_args *uap, user_addr_t *retval)
        for (shm_handle = CAST_DOWN(void *, shmseg->u.shm_internal);/* tunnel */
            shm_handle != NULL;
            shm_handle = shm_handle->shm_handle_next) {
        for (shm_handle = CAST_DOWN(void *, shmseg->u.shm_internal);/* tunnel */
            shm_handle != NULL;
            shm_handle = shm_handle->shm_handle_next) {
+               vm_map_size_t chunk_size;
+
+               assert(mapped_size < map_size);
+               chunk_size = shm_handle->shm_handle_size;
+               if (chunk_size > map_size - mapped_size) {
+                       /*
+                        * Partial mapping of last chunk due to
+                        * page size mismatch.
+                        */
+                       assert(vm_map_page_shift(current_map()) < PAGE_SHIFT);
+                       assert(shm_handle->shm_handle_next == NULL);
+                       chunk_size = map_size - mapped_size;
+               }
                rv = vm_map_enter_mem_object(
                        current_map(),          /* process map */
                        &attach_va,             /* attach address */
                rv = vm_map_enter_mem_object(
                        current_map(),          /* process map */
                        &attach_va,             /* attach address */
-                       shm_handle->shm_handle_size, /* segment size */
+                       chunk_size,             /* size to map */
                        (mach_vm_offset_t)0,    /* alignment mask */
                        VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
                        VM_MAP_KERNEL_FLAGS_NONE,
                        (mach_vm_offset_t)0,    /* alignment mask */
                        VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
                        VM_MAP_KERNEL_FLAGS_NONE,
@@ -533,8 +551,8 @@ shmat(struct proc *p, struct shmat_args *uap, user_addr_t *retval)
                        goto out;
                }
 
                        goto out;
                }
 
-               mapped_size += shm_handle->shm_handle_size;
-               attach_va = attach_va + shm_handle->shm_handle_size;
+               mapped_size += chunk_size;
+               attach_va = attach_va + chunk_size;
        }
 
        shmmap_s->shmid = uap->shmid;
        }
 
        shmmap_s->shmid = uap->shmid;
@@ -1185,9 +1203,9 @@ IPCS_shm_sysctl(__unused struct sysctl_oid *oidp, __unused void *arg1,
        union {
                struct user32_IPCS_command u32;
                struct user_IPCS_command u64;
        union {
                struct user32_IPCS_command u32;
                struct user_IPCS_command u64;
-       } ipcs;
-       struct user32_shmid_ds shmid_ds32 = {}; /* post conversion, 32 bit version */
-       struct user_shmid_ds   shmid_ds;        /* 64 bit version */
+       } ipcs = { };
+       struct user32_shmid_ds shmid_ds32 = { }; /* post conversion, 32 bit version */
+       struct user_shmid_ds   shmid_ds = { };   /* 64 bit version */
        void *shmid_dsp;
        size_t ipcs_sz = sizeof(struct user_IPCS_command);
        size_t shmid_ds_sz = sizeof(struct user_shmid_ds);
        void *shmid_dsp;
        size_t ipcs_sz = sizeof(struct user_IPCS_command);
        size_t shmid_ds_sz = sizeof(struct user_shmid_ds);