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