1 /*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <portability.h>
18 #include <unistd.h>
19 #include <stdarg.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <errno.h>
23 #include <errno_portable.h>
24 #include <filefd_portable.h>
25 #include <signal_portable.h>
26 #include <sys/atomics.h>
27
28 #define PORTABLE_TAG "filefd_portable"
29 #include <log_portable.h>
30
31 /*
32 * Maintaining a list of special file descriptors in lib-portable:
33 * ---------------------------------------------------------------
34 *
35 * These are file descriptors which were opened with system calls
36 * which make it possible to read kernel data structures via the
37 * read system call. See man pages for:
38 * signalfd(2)
39 * eventfd(2)
40 * timerfd_create(2)
41 *
42 * The files conditioned with signalfd(2) need to have their reads
43 * intercepted to correct signal numbers. This is done using this table
44 * of mapped files.
45 *
46 * The signalfd(2) semantics are maintained across execve(2) by exporting
47 * and importing environment variables for file descriptors that are not
48 * marked as close-on-execute. For example testing import code with:
49 * Eg:
50 * export ANDROID_PORTABLE_MAPPED_FILE_DESCRIPTORS=10,17
51 * export ANDROID_PORTABLE_MAPPED_FILE_TYPES=2,1
52 *
53 * Where
54 * filefd_mapped_file[10] = SIGNAL_FD_TYPE:2
55 * filefd_FD_CLOEXEC_file[10] = 0;
56 * and
57 * filefd_mapped_file[17] = EVENT_FD_TYPE:1
58 * filefd_FD_CLOEXEC_file[17] = 0;
59 *
60 * A table of CLOEXEC_files is maintained via call-backs
61 * in open_portable() and fcntl_portable() which indicates
62 * the files with close-on-execute semantics.
63 *
64 * The signalfd(2) fork(2) and thread semantics are not
65 * affected by the mapping of signalfd() file descriptor reads.
66 *
67 * This algorithm requires that threads have the same sharing
68 * attributes for file descriptors and memory and will be disabled
69 * by a call from clone() if the environment is unsuitable for it's use.
70 */
71
72 static char *fd_env_name = "ANDROID_PORTABLE_MAPPED_FILE_DESCRIPTORS";
73 static char *type_env_name = "ANDROID_PORTABLE_MAPPED_FILE_TYPES";
74 static enum filefd_type filefd_mapped_file[__FD_SETSIZE];
75 static int filefd_FD_CLOEXEC_file[__FD_SETSIZE];
76
77 static volatile int filefd_mapped_files = 0;
78 static volatile int filefd_enabled = 1;
79
80 /*
81 * Assuming sizeof(int)==4, and __FD_SETSIZE < 10000 each token will
82 * occupy a maximum of 5 characters (4 digits + delimiter:','). The tokens
83 * are the numbers above, a file descriptor (0..9999), and the filefd_type's
84 * which are a single digit.
85 *
86 * The arrays used to manipulate the environment variables are allocated using
87 * malloc to avoid overrunning the stack.
88 */
89 #if __FD_SETSIZE >= 10000
90 #error MAX_ENV_SIZE must be increased
91 #endif
92
93 #define MAX_ENV_SIZE (__FD_SETSIZE * 5)
94
export_fd_env()95 static int export_fd_env()
96 {
97 const int max_env_size = MAX_ENV_SIZE;
98 int type_env_bytes_remaining = max_env_size;
99 char *type_env_allocated = NULL, *type_env;
100 int fd_env_bytes_remaining = max_env_size;
101 char *fd_env_allocated = NULL, *fd_env;
102 int exported_file_descriptors = 0;
103 enum filefd_type fd_type;
104 int overwrite = 1;
105 int fd_count = 0;
106 int saved_errno;
107 int fd_cloexec;
108 int len;
109 int rv1;
110 int rv2;
111 int rv;
112 int fd;
113
114 ALOGV("%s:() {", __func__);
115
116 saved_errno = *REAL(__errno)();
117
118 type_env_allocated = malloc(max_env_size);
119 fd_env_allocated = malloc(max_env_size);
120 if (type_env_allocated == NULL || fd_env_allocated == NULL) {
121 ALOGE("%s: type_env_allocated:%p, fd_env_allocated:%p; FIXME!", __func__,
122 type_env_allocated, fd_env_allocated);
123
124 rv = -1;
125 goto done;
126 } else {
127 ALOGV("%s: type_env_allocated:%p, fd_env_allocated:%p;", __func__,
128 type_env_allocated, fd_env_allocated);
129 }
130
131 type_env = type_env_allocated;
132 fd_env = fd_env_allocated;
133
134 for (fd = 0; fd < __FD_SETSIZE; fd++) {
135 fd_type = filefd_mapped_file[fd];
136 if (fd_type != UNUSED_FD_TYPE) {
137 ++fd_count;
138 ALOGV("%s: fd_type = %d = filefd_mapped_file[fd:%d]; ++fdcount:%d;", __func__,
139 fd_type, fd, fd_count);
140
141 fd_cloexec = filefd_FD_CLOEXEC_file[fd];
142 ALOGV("%s: fd_cloexec = %d = filefd_FD_CLOEXEC_file[fd:%d];", __func__,
143 fd_cloexec, fd);
144
145 if (fd_cloexec == 0) {
146 rv = snprintf(fd_env, fd_env_bytes_remaining, "%d,", fd);
147 ASSERT(rv > 0);
148 fd_env += rv;
149 fd_env_bytes_remaining -= rv;
150 rv = snprintf(type_env, type_env_bytes_remaining, "%d,", filefd_mapped_file[fd]);
151 ASSERT(rv > 0);
152 type_env += rv;
153 type_env_bytes_remaining -= rv;
154 exported_file_descriptors++;
155 }
156
157 /*
158 * There is a chance of inconsistent results here if
159 * another thread is updating the array while it was
160 * being copied, but this code is only run during exec
161 * so the state of the file descriptors that the child
162 * sees will be inconsistent anyway.
163 */
164 if (fd_count == filefd_mapped_files)
165 break;
166 }
167 }
168 if (fd_count != filefd_mapped_files) {
169 ALOGE("%s: fd_count:%d != filefd_mapped_files:%d; [Likely Race; add futex?]", __func__,
170 fd_count, filefd_mapped_files);
171
172 }
173 if (exported_file_descriptors == 0) {
174 rv1 = unsetenv(fd_env_name);
175 rv2 = unsetenv(type_env_name);
176 if (rv1 != 0 || rv2 != 0) {
177 ALOGV("%s: Note: unsetenv() failed!", __func__);
178 }
179 rv = 0;
180 } else {
181 if (fd_env > fd_env_allocated) {
182 fd_env--; /* backup fd_env to last ',' */
183 }
184 *fd_env = '\0';
185
186 if (type_env > type_env_allocated) {
187 type_env--; /* backup type_env to last ',' */
188 }
189 *type_env = '\0';
190
191 rv = setenv(fd_env_name, fd_env_allocated, overwrite);
192 if (rv != 0) {
193 ALOGE("%s: rv:%d = setenv(fd_env_name:'%s', fd_env_allocated:'%s' ...);", __func__,
194 rv, fd_env_name, fd_env_allocated);
195 } else {
196 ALOGV("%s: rv:%d = setenv(fd_env_name:'%s', fd_env_allocated:'%s' ...);", __func__,
197 rv, fd_env_name, fd_env_allocated);
198 }
199 if (rv != 0) goto done;
200
201 rv = setenv(type_env_name, type_env_allocated, overwrite);
202
203 if (rv != 0) {
204 ALOGE("%s: rv:%d = setenv(type_env_name:'%s', type_env_allocated:'%s' ...);",
205 __func__, rv, type_env_name, type_env_allocated);
206 } else {
207 ALOGV("%s: rv:%d = setenv(type_env_name:'%s', type_env_allocated:'%s' ...);",
208 __func__, rv, type_env_name, type_env_allocated);
209 }
210 }
211
212 done:
213 if (type_env_allocated)
214 free(type_env_allocated);
215
216 if (fd_env_allocated)
217 free(fd_env_allocated);
218
219 *REAL(__errno)() = saved_errno;
220
221 ALOGV("%s: return(rv:%d); }", __func__, rv);
222 return rv;
223 }
224
225
import_fd_env(int verify)226 static int import_fd_env(int verify)
227 {
228 char *type_env_allocated = NULL;
229 char *fd_env_allocated = NULL;
230 char *type_token_saved_ptr;
231 char *fd_token_saved_ptr;
232 enum filefd_type fd_type;
233 char *type_env, *fd_env;
234 int saved_errno;
235 char *type_token;
236 char *fd_token;
237 int rv = 0;
238 int fd;
239
240 ALOGV("%s:(verify:%d) {", __func__, verify);
241
242 saved_errno = *REAL(__errno)();
243
244 /*
245 * get file descriptor environment pointer and make a
246 * a copy of the string.
247 */
248 fd_env = getenv(fd_env_name);
249 if (fd_env == NULL) {
250 ALOGV("%s: fd_env = NULL = getenv('%s');", __func__,
251 fd_env_name);
252 goto done;
253 } else {
254 ALOGV("%s: fd_env = '%s' = getenv('%s');", __func__,
255 fd_env, fd_env_name);
256
257 fd_env_allocated = malloc(strlen(fd_env)+1);
258 if (fd_env_allocated == NULL) {
259 ALOGE("%s: fd_env_allocated = NULL; malloc failed", __func__);
260 goto done;
261 }
262 strcpy(fd_env_allocated, fd_env);
263 }
264
265 /*
266 * get file descriptor environment pointer and make a copy of
267 * the string to our stack.
268 */
269 type_env = getenv(type_env_name);
270 if (type_env == NULL) {
271 ALOGV("%s: type_env = NULL = getenv(type_env_name:'%s');", __func__,
272 type_env_name);
273 goto done;
274 } else {
275 ALOGV("%s: type_env = '%s' = getenv(type_env_name:'%s');", __func__,
276 type_env, type_env_name);
277
278 type_env_allocated = malloc(strlen(type_env)+1);
279 if (type_env_allocated == NULL) {
280 ALOGE("%s: type_env_allocated = NULL; malloc failed", __func__);
281 goto done;
282 }
283 strcpy(type_env_allocated, type_env);
284 }
285
286 /*
287 * Setup strtok_r(), use it to parse the env tokens, and
288 * initialise the filefd_mapped_file array.
289 */
290 fd_token = strtok_r(fd_env_allocated, ",", &fd_token_saved_ptr);
291 type_token = strtok_r(type_env_allocated, ",", &type_token_saved_ptr);
292 while (fd_token && type_token) {
293 fd = atoi(fd_token);
294 ASSERT(fd >= 0 );
295 ASSERT(fd < __FD_SETSIZE);
296
297 fd_type = (enum filefd_type) atoi(type_token);
298 ASSERT(fd_type > UNUSED_FD_TYPE);
299 ASSERT(fd_type < MAX_FD_TYPE);
300
301 if (fd >= 0 && fd < __FD_SETSIZE) {
302 if (fd_type > UNUSED_FD_TYPE && fd_type < MAX_FD_TYPE) {
303 if (verify) {
304 ASSERT(filefd_mapped_file[fd] == fd_type);
305 ALOGV("%s: filefd_mapped_file[fd:%d] == fd_type:%d;", __func__,
306 fd, fd_type);
307 } else {
308 ASSERT(filefd_mapped_file[fd] == UNUSED_FD_TYPE);
309
310 __atomic_inc(&filefd_mapped_files);
311 ALOGV("%s: ++filefd_mapped_files:%d;", __func__,
312 filefd_mapped_files);
313
314 filefd_mapped_file[fd] = fd_type;
315 ALOGV("%s: filefd_mapped_file[fd:%d] = fd_type:%d;", __func__,
316 fd, fd_type);
317 }
318 }
319 }
320
321 fd_token = strtok_r(NULL, ",", &fd_token_saved_ptr);
322 type_token = strtok_r(NULL, ",", &type_token_saved_ptr);
323 }
324
325 done:
326 if (type_env_allocated)
327 free(type_env_allocated);
328 if (fd_env_allocated)
329 free(fd_env_allocated);
330
331 *REAL(__errno)() = saved_errno;
332
333 ALOGV("%s: return(rv:%d); }", __func__, rv);
334 return rv;
335 }
336
337
338 /*
339 * This function will get run by the linker when the library is loaded.
340 */
linker_import_fd_env(void)341 static void __attribute__ ((constructor)) linker_import_fd_env(void)
342 {
343 int rv;
344 int verify_consistancy = 0;
345
346 ALOGV(" ");
347 ALOGV("%s() {", __func__);
348
349 rv = import_fd_env(verify_consistancy); /* File type table not verified. */
350
351 ALOGV("%s: }", __func__);
352 }
353
354
filefd_opened(int fd,enum filefd_type fd_type)355 __hidden void filefd_opened(int fd, enum filefd_type fd_type)
356 {
357 ALOGV("%s(fd:%d) {", __func__, fd);
358
359 if (fd >= 0 && fd < __FD_SETSIZE) {
360 if (filefd_mapped_file[fd] == UNUSED_FD_TYPE) {
361 __atomic_inc(&filefd_mapped_files);
362 filefd_mapped_file[fd] = fd_type;
363 }
364 ASSERT(filefd_mapped_file[fd] == fd_type);
365 }
366
367 ALOGV("%s: }", __func__);
368 }
369
filefd_closed(int fd)370 __hidden void filefd_closed(int fd)
371 {
372 ALOGV("%s(fd:%d) {", __func__, fd);
373
374 if (fd >= 0 && fd < __FD_SETSIZE) {
375 if (filefd_mapped_file[fd] != UNUSED_FD_TYPE) {
376 filefd_mapped_file[fd] = UNUSED_FD_TYPE;
377 filefd_FD_CLOEXEC_file[fd] = 0;
378 __atomic_dec(&filefd_mapped_files);
379 }
380 }
381 ALOGV("%s: }", __func__);
382 }
383
384
filefd_CLOEXEC_enabled(int fd)385 __hidden void filefd_CLOEXEC_enabled(int fd)
386 {
387 ALOGV("%s:(fd:%d) {", __func__, fd);
388
389 if (fd >= 0 && fd < __FD_SETSIZE) {
390 filefd_FD_CLOEXEC_file[fd] = 1;
391 }
392
393 ALOGV("%s: }", __func__);
394 }
395
filefd_CLOEXEC_disabled(int fd)396 __hidden void filefd_CLOEXEC_disabled(int fd)
397 {
398 ALOGV("%s:(fd:%d) {", __func__, fd);
399
400 if (fd >= 0 && fd < __FD_SETSIZE) {
401 filefd_FD_CLOEXEC_file[fd] = 0;
402 }
403
404 ALOGV("%s: }", __func__);
405 }
406
407
filefd_disable_mapping()408 __hidden void filefd_disable_mapping()
409 {
410 ALOGV("%s:() {", __func__);
411
412 filefd_enabled = 0;
413
414 ALOGV("%s: }", __func__);
415 }
416
417
WRAP(close)418 int WRAP(close)(int fd)
419 {
420 int rv;
421
422 ALOGV(" ");
423 ALOGV("%s(fd:%d) {", __func__, fd);
424
425 rv = REAL(close)(fd);
426 filefd_closed(fd);
427
428 ALOGV("%s: return(rv:%d); }", __func__, rv);
429 return rv;
430 }
431
432
WRAP(read)433 int WRAP(read)(int fd, void *buf, size_t count)
434 {
435 int rv;
436 enum filefd_type fd_type;
437
438 ALOGV(" ");
439 ALOGV("%s(fd:%d, buf:0x%p, count:%d) {", __func__,
440 fd, buf, count);
441
442 fd_type = filefd_mapped_file[fd];
443 ALOGV("%s:fd_type:%d", __func__,
444 fd_type);
445
446 switch (fd_type) {
447 /* Reads on these descriptors are portable; no need to be mapped. */
448 case UNUSED_FD_TYPE:
449 case EVENT_FD_TYPE:
450 case INOTIFY_FD_TYPE:
451 case TIMER_FD_TYPE:
452 rv = REAL(read)(fd, buf, count);
453 break;
454
455 /* The read() of a signalfd() file descriptor needs to be mapped. */
456 case SIGNAL_FD_TYPE:
457 if (filefd_enabled) {
458 rv = read_signalfd_mapper(fd, buf, count);
459 } else {
460 rv = REAL(read)(fd, buf, count);
461 }
462 break;
463
464 default:
465 ALOGE("Unknown fd_type:%d!", fd_type);
466 rv = REAL(read)(fd, buf, count);
467 break;
468 }
469
470 ALOGV("%s: return(rv:%d); }", __func__, rv);
471 return rv;
472 }
473
474
475 /*
476 * Export PORTABLE environment variables before execve().
477 * Tries a second time if it detects an extremely unlikely
478 * race condition.
479 */
WRAP(execve)480 int WRAP(execve)(const char *filename, char *const argv[], char *const envp[])
481 {
482 int rv;
483 int mapped_files = filefd_mapped_files;
484 int verify_consistancy = 1;
485
486 ALOGV(" ");
487 ALOGV("%s(filename:%p, argv:%p, envp:%p) {", __func__,
488 filename, argv, envp);
489
490 export_fd_env();
491
492 if (mapped_files != filefd_mapped_files) {
493 export_fd_env();
494 }
495 import_fd_env(verify_consistancy); /* File type table consistancy verified. */
496
497 rv = REAL(execve)(filename, argv, envp);
498
499 ALOGV("%s: return(rv:%d); }", __func__, rv);
500 return rv;
501 }
502
503