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 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 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 */ 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 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 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 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 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 408 __hidden void filefd_disable_mapping() 409 { 410 ALOGV("%s:() {", __func__); 411 412 filefd_enabled = 0; 413 414 ALOGV("%s: }", __func__); 415 } 416 417 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 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 */ 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