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