1 /* Copyright 2016 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 */ 5 6 #include <sys/cdefs.h> 7 #include <sys/mman.h> 8 #ifdef __BIONIC__ 9 #include <cutils/ashmem.h> 10 #else 11 #include <sys/shm.h> 12 #endif 13 #include <errno.h> 14 #include <syslog.h> 15 #include <stdio.h> 16 #include <string.h> 17 18 #include "cras_shm.h" 19 20 /* Set the correct SELinux label for SHM fds. */ 21 static void cras_shm_restorecon(int fd) 22 { 23 #ifdef CRAS_SELINUX 24 char fd_proc_path[64]; 25 26 if (snprintf(fd_proc_path, sizeof(fd_proc_path), "/proc/self/fd/%d", fd) < 0) { 27 syslog(LOG_WARNING, 28 "Couldn't construct proc symlink path of fd: %d", fd); 29 return; 30 } 31 32 /* Get the actual file-path for this fd. */ 33 char *path = realpath(fd_proc_path, NULL); 34 if (path == NULL) { 35 syslog(LOG_WARNING, "Couldn't run realpath() for %s: %s", 36 fd_proc_path, strerror(errno)); 37 return; 38 } 39 40 if (cras_selinux_restorecon(path) < 0) { 41 syslog(LOG_WARNING, "Restorecon on %s failed: %s", 42 fd_proc_path, strerror(errno)); 43 } 44 45 free(path); 46 #endif 47 } 48 49 #ifdef __BIONIC__ 50 51 int cras_shm_open_rw (const char *name, size_t size) 52 { 53 int fd; 54 55 /* Eliminate the / in the shm_name. */ 56 if (name[0] == '/') 57 name++; 58 fd = ashmem_create_region(name, size); 59 if (fd < 0) { 60 fd = -errno; 61 syslog(LOG_ERR, "failed to ashmem_create_region %s: %s\n", 62 name, strerror(-fd)); 63 } 64 return fd; 65 } 66 67 int cras_shm_reopen_ro (const char *name, int fd) 68 { 69 /* After mmaping the ashmem read/write, change it's protection 70 bits to disallow further write access. */ 71 if (ashmem_set_prot_region(fd, PROT_READ) != 0) { 72 fd = -errno; 73 syslog(LOG_ERR, 74 "failed to ashmem_set_prot_region %s: %s\n", 75 name, strerror(-fd)); 76 } 77 return fd; 78 } 79 80 void cras_shm_close_unlink (const char *name, int fd) 81 { 82 close(fd); 83 } 84 85 #else 86 87 int cras_shm_open_rw (const char *name, size_t size) 88 { 89 int fd; 90 int rc; 91 92 fd = shm_open(name, O_CREAT | O_EXCL | O_RDWR, 0600); 93 if (fd < 0) { 94 fd = -errno; 95 syslog(LOG_ERR, "failed to shm_open %s: %s\n", 96 name, strerror(-fd)); 97 return fd; 98 } 99 rc = ftruncate(fd, size); 100 if (rc) { 101 rc = -errno; 102 syslog(LOG_ERR, "failed to set size of shm %s: %s\n", 103 name, strerror(-rc)); 104 return rc; 105 } 106 107 cras_shm_restorecon(fd); 108 109 return fd; 110 } 111 112 int cras_shm_reopen_ro (const char *name, int fd) 113 { 114 /* Open a read-only copy to dup and pass to clients. */ 115 fd = shm_open(name, O_RDONLY, 0); 116 if (fd < 0) { 117 fd = -errno; 118 syslog(LOG_ERR, 119 "Failed to re-open shared memory '%s' read-only: %s", 120 name, strerror(-fd)); 121 } 122 return fd; 123 } 124 125 void cras_shm_close_unlink (const char *name, int fd) 126 { 127 shm_unlink(name); 128 close(fd); 129 } 130 131 #endif 132 133 void *cras_shm_setup(const char *name, 134 size_t mmap_size, 135 int *rw_fd_out, 136 int *ro_fd_out) 137 { 138 int rw_shm_fd = cras_shm_open_rw(name, mmap_size); 139 if (rw_shm_fd < 0) 140 return NULL; 141 142 /* mmap shm. */ 143 void *exp_state = mmap(NULL, mmap_size, 144 PROT_READ | PROT_WRITE, MAP_SHARED, 145 rw_shm_fd, 0); 146 if (exp_state == (void *)-1) 147 return NULL; 148 149 /* Open a read-only copy to dup and pass to clients. */ 150 int ro_shm_fd = cras_shm_reopen_ro(name, rw_shm_fd); 151 if (ro_shm_fd < 0) 152 return NULL; 153 154 *rw_fd_out = rw_shm_fd; 155 *ro_fd_out = ro_shm_fd; 156 157 return exp_state; 158 } 159