system/corennnnn
Révision | 2895e11453da7afc326864a097ff59833a0bffea (tree) |
---|---|
l'heure | 2016-07-16 04:34:06 |
Auteur | Mark Salyzyn <salyzyn@goog...> |
Commiter | Steve Kondik |
libcutils: ashmem check fd validity
- collect st_rdev on open, or when required, for /dev/ashmem.
- check in all cases if fd is a character device and matches rdev.
- requires that we have open, read and write access to /dev/ashmem
NB: ashmem libcutil library entry points can no longer be called in
Bug: 26871259
Change-Id: I9a17e33317a9be795131473a51c16f761b5f7407
@@ -22,6 +22,7 @@ | ||
22 | 22 | |
23 | 23 | #include <errno.h> |
24 | 24 | #include <fcntl.h> |
25 | +#include <pthread.h> | |
25 | 26 | #include <string.h> |
26 | 27 | #include <sys/ioctl.h> |
27 | 28 | #include <sys/stat.h> |
@@ -34,6 +35,89 @@ | ||
34 | 35 | |
35 | 36 | #define ASHMEM_DEVICE "/dev/ashmem" |
36 | 37 | |
38 | +/* ashmem identity */ | |
39 | +static dev_t __ashmem_rdev; | |
40 | +/* | |
41 | + * If we trigger a signal handler in the middle of locked activity and the | |
42 | + * signal handler calls ashmem, we could get into a deadlock state. | |
43 | + */ | |
44 | +static pthread_mutex_t __ashmem_lock = PTHREAD_MUTEX_INITIALIZER; | |
45 | + | |
46 | +/* logistics of getting file descriptor for ashmem */ | |
47 | +static int __ashmem_open_locked() | |
48 | +{ | |
49 | + int ret; | |
50 | + struct stat st; | |
51 | + | |
52 | + int fd = TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE, O_RDWR)); | |
53 | + if (fd < 0) { | |
54 | + return fd; | |
55 | + } | |
56 | + | |
57 | + ret = TEMP_FAILURE_RETRY(fstat(fd, &st)); | |
58 | + if (ret < 0) { | |
59 | + int save_errno = errno; | |
60 | + close(fd); | |
61 | + errno = save_errno; | |
62 | + return ret; | |
63 | + } | |
64 | + if (!S_ISCHR(st.st_mode) || !st.st_rdev) { | |
65 | + close(fd); | |
66 | + errno = ENOTTY; | |
67 | + return -1; | |
68 | + } | |
69 | + | |
70 | + __ashmem_rdev = st.st_rdev; | |
71 | + return fd; | |
72 | +} | |
73 | + | |
74 | +static int __ashmem_open() | |
75 | +{ | |
76 | + int fd; | |
77 | + | |
78 | + pthread_mutex_lock(&__ashmem_lock); | |
79 | + fd = __ashmem_open_locked(); | |
80 | + pthread_mutex_unlock(&__ashmem_lock); | |
81 | + | |
82 | + return fd; | |
83 | +} | |
84 | + | |
85 | +/* Make sure file descriptor references ashmem, negative number means false */ | |
86 | +static int __ashmem_is_ashmem(int fd) | |
87 | +{ | |
88 | + dev_t rdev; | |
89 | + struct stat st; | |
90 | + | |
91 | + if (TEMP_FAILURE_RETRY(fstat(fd, &st)) < 0) { | |
92 | + return -1; | |
93 | + } | |
94 | + | |
95 | + if (S_ISCHR(st.st_mode) && st.st_rdev) { | |
96 | + pthread_mutex_lock(&__ashmem_lock); | |
97 | + rdev = __ashmem_rdev; | |
98 | + if (rdev) { | |
99 | + pthread_mutex_unlock(&__ashmem_lock); | |
100 | + } else { | |
101 | + int fd = __ashmem_open_locked(); | |
102 | + if (fd < 0) { | |
103 | + pthread_mutex_unlock(&__ashmem_lock); | |
104 | + return -1; | |
105 | + } | |
106 | + rdev = __ashmem_rdev; | |
107 | + pthread_mutex_unlock(&__ashmem_lock); | |
108 | + | |
109 | + close(fd); | |
110 | + } | |
111 | + | |
112 | + if (st.st_rdev == rdev) { | |
113 | + return 0; | |
114 | + } | |
115 | + } | |
116 | + | |
117 | + errno = ENOTTY; | |
118 | + return -1; | |
119 | +} | |
120 | + | |
37 | 121 | /* |
38 | 122 | * ashmem_create_region - creates a new ashmem region and returns the file |
39 | 123 | * descriptor, or <0 on error |
@@ -45,7 +129,7 @@ int ashmem_create_region(const char *name, size_t size) | ||
45 | 129 | { |
46 | 130 | int ret, save_errno; |
47 | 131 | |
48 | - int fd = TEMP_FAILURE_RETRY(open(ASHMEM_DEVICE, O_RDWR)); | |
132 | + int fd = __ashmem_open(); | |
49 | 133 | if (fd < 0) { |
50 | 134 | return fd; |
51 | 135 | } |
@@ -76,22 +160,44 @@ error: | ||
76 | 160 | |
77 | 161 | int ashmem_set_prot_region(int fd, int prot) |
78 | 162 | { |
163 | + int ret = __ashmem_is_ashmem(fd); | |
164 | + if (ret < 0) { | |
165 | + return ret; | |
166 | + } | |
167 | + | |
79 | 168 | return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_SET_PROT_MASK, prot)); |
80 | 169 | } |
81 | 170 | |
82 | 171 | int ashmem_pin_region(int fd, size_t offset, size_t len) |
83 | 172 | { |
84 | 173 | struct ashmem_pin pin = { offset, len }; |
174 | + | |
175 | + int ret = __ashmem_is_ashmem(fd); | |
176 | + if (ret < 0) { | |
177 | + return ret; | |
178 | + } | |
179 | + | |
85 | 180 | return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_PIN, &pin)); |
86 | 181 | } |
87 | 182 | |
88 | 183 | int ashmem_unpin_region(int fd, size_t offset, size_t len) |
89 | 184 | { |
90 | 185 | struct ashmem_pin pin = { offset, len }; |
186 | + | |
187 | + int ret = __ashmem_is_ashmem(fd); | |
188 | + if (ret < 0) { | |
189 | + return ret; | |
190 | + } | |
191 | + | |
91 | 192 | return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_UNPIN, &pin)); |
92 | 193 | } |
93 | 194 | |
94 | 195 | int ashmem_get_size_region(int fd) |
95 | 196 | { |
197 | + int ret = __ashmem_is_ashmem(fd); | |
198 | + if (ret < 0) { | |
199 | + return ret; | |
200 | + } | |
201 | + | |
96 | 202 | return TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL)); |
97 | 203 | } |