Home | History | Annotate | Download | only in common
      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