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