• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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. */
cras_shm_restorecon(int fd)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 
cras_shm_open_rw(const char * name,size_t size)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 
cras_shm_reopen_ro(const char * name,int fd)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 
cras_shm_close_unlink(const char * name,int fd)80 void cras_shm_close_unlink (const char *name, int fd)
81 {
82 	close(fd);
83 }
84 
85 #else
86 
cras_shm_open_rw(const char * name,size_t size)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 
cras_shm_reopen_ro(const char * name,int fd)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 
cras_shm_close_unlink(const char * name,int fd)125 void cras_shm_close_unlink (const char *name, int fd)
126 {
127 	shm_unlink(name);
128 	close(fd);
129 }
130 
131 #endif
132 
cras_shm_setup(const char * name,size_t mmap_size,int * rw_fd_out,int * ro_fd_out)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