1 /* 2 ** 3 ** Copyright 2010, The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 #include <errno.h> 18 #include <fcntl.h> 19 #include <unistd.h> 20 #include <sys/stat.h> 21 #include <sys/mman.h> 22 #include <private/android_filesystem_config.h> 23 #include "package.h" 24 25 /* 26 * WARNING WARNING WARNING WARNING 27 * 28 * The following code runs as root on production devices, before 29 * the run-as command has dropped the uid/gid. Hence be very 30 * conservative and keep in mind the following: 31 * 32 * - Performance does not matter here, clarity and safety of the code 33 * does however. Documentation is a must. 34 * 35 * - Avoid calling C library functions with complex implementations 36 * like malloc() and printf(). You want to depend on simple system 37 * calls instead, which behaviour is not going to be altered in 38 * unpredictible ways by environment variables or system properties. 39 * 40 * - Do not trust user input and/or the filesystem whenever possible. 41 * 42 */ 43 44 /* The file containing the list of installed packages on the system */ 45 #define PACKAGES_LIST_FILE "/data/system/packages.list" 46 47 /* Copy 'srclen' string bytes from 'src' into buffer 'dst' of size 'dstlen' 48 * This function always zero-terminate the destination buffer unless 49 * 'dstlen' is 0, even in case of overflow. 50 * Returns a pointer into the src string, leaving off where the copy 51 * has stopped. The copy will stop when dstlen, srclen or a null 52 * character on src has been reached. 53 */ 54 static const char* 55 string_copy(char* dst, size_t dstlen, const char* src, size_t srclen) 56 { 57 const char* srcend = src + srclen; 58 const char* dstend = dst + dstlen; 59 60 if (dstlen == 0) 61 return src; 62 63 dstend--; /* make room for terminating zero */ 64 65 while (dst < dstend && src < srcend && *src != '\0') 66 *dst++ = *src++; 67 68 *dst = '\0'; /* zero-terminate result */ 69 return src; 70 } 71 72 /* Open 'filename' and map it into our address-space. 73 * Returns buffer address, or NULL on error 74 * On exit, *filesize will be set to the file's size, or 0 on error 75 */ 76 static void* 77 map_file(const char* filename, size_t* filesize) 78 { 79 int fd, ret, old_errno; 80 struct stat st; 81 size_t length = 0; 82 void* address = NULL; 83 gid_t oldegid; 84 85 *filesize = 0; 86 87 /* 88 * Temporarily switch effective GID to allow us to read 89 * the packages file 90 */ 91 92 oldegid = getegid(); 93 if (setegid(AID_PACKAGE_INFO) < 0) { 94 return NULL; 95 } 96 97 /* open the file for reading */ 98 fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY)); 99 if (fd < 0) { 100 return NULL; 101 } 102 103 /* restore back to our old egid */ 104 if (setegid(oldegid) < 0) { 105 goto EXIT; 106 } 107 108 /* get its size */ 109 ret = TEMP_FAILURE_RETRY(fstat(fd, &st)); 110 if (ret < 0) 111 goto EXIT; 112 113 /* Ensure that the file is owned by the system user */ 114 if ((st.st_uid != AID_SYSTEM) || (st.st_gid != AID_PACKAGE_INFO)) { 115 goto EXIT; 116 } 117 118 /* Ensure that the file has sane permissions */ 119 if ((st.st_mode & S_IWOTH) != 0) { 120 goto EXIT; 121 } 122 123 /* Ensure that the size is not ridiculously large */ 124 length = (size_t)st.st_size; 125 if ((off_t)length != st.st_size) { 126 errno = ENOMEM; 127 goto EXIT; 128 } 129 130 /* Memory-map the file now */ 131 address = TEMP_FAILURE_RETRY(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0)); 132 if (address == MAP_FAILED) { 133 address = NULL; 134 goto EXIT; 135 } 136 137 /* We're good, return size */ 138 *filesize = length; 139 140 EXIT: 141 /* close the file, preserve old errno for better diagnostics */ 142 old_errno = errno; 143 close(fd); 144 errno = old_errno; 145 146 return address; 147 } 148 149 /* unmap the file, but preserve errno */ 150 static void 151 unmap_file(void* address, size_t size) 152 { 153 int old_errno = errno; 154 TEMP_FAILURE_RETRY(munmap(address, size)); 155 errno = old_errno; 156 } 157 158 /* Check that a given directory: 159 * - exists 160 * - is owned by a given uid/gid 161 * - is a real directory, not a symlink 162 * - isn't readable or writable by others 163 * 164 * Return 0 on success, or -1 on error. 165 * errno is set to EINVAL in case of failed check. 166 */ 167 static int 168 check_directory_ownership(const char* path, uid_t uid) 169 { 170 int ret; 171 struct stat st; 172 173 do { 174 ret = lstat(path, &st); 175 } while (ret < 0 && errno == EINTR); 176 177 if (ret < 0) 178 return -1; 179 180 /* must be a real directory, not a symlink */ 181 if (!S_ISDIR(st.st_mode)) 182 goto BAD; 183 184 /* must be owned by specific uid/gid */ 185 if (st.st_uid != uid || st.st_gid != uid) 186 goto BAD; 187 188 /* must not be readable or writable by others */ 189 if ((st.st_mode & (S_IROTH|S_IWOTH)) != 0) 190 goto BAD; 191 192 /* everything ok */ 193 return 0; 194 195 BAD: 196 errno = EINVAL; 197 return -1; 198 } 199 200 /* This function is used to check the data directory path for safety. 201 * We check that every sub-directory is owned by the 'system' user 202 * and exists and is not a symlink. We also check that the full directory 203 * path is properly owned by the user ID. 204 * 205 * Return 0 on success, -1 on error. 206 */ 207 int 208 check_data_path(const char* dataPath, uid_t uid) 209 { 210 int nn; 211 212 /* the path should be absolute */ 213 if (dataPath[0] != '/') { 214 errno = EINVAL; 215 return -1; 216 } 217 218 /* look for all sub-paths, we do that by finding 219 * directory separators in the input path and 220 * checking each sub-path independently 221 */ 222 for (nn = 1; dataPath[nn] != '\0'; nn++) 223 { 224 char subpath[PATH_MAX]; 225 226 /* skip non-separator characters */ 227 if (dataPath[nn] != '/') 228 continue; 229 230 /* handle trailing separator case */ 231 if (dataPath[nn+1] == '\0') { 232 break; 233 } 234 235 /* found a separator, check that dataPath is not too long. */ 236 if (nn >= (int)(sizeof subpath)) { 237 errno = EINVAL; 238 return -1; 239 } 240 241 /* reject any '..' subpath */ 242 if (nn >= 3 && 243 dataPath[nn-3] == '/' && 244 dataPath[nn-2] == '.' && 245 dataPath[nn-1] == '.') { 246 errno = EINVAL; 247 return -1; 248 } 249 250 /* copy to 'subpath', then check ownership */ 251 memcpy(subpath, dataPath, nn); 252 subpath[nn] = '\0'; 253 254 if (check_directory_ownership(subpath, AID_SYSTEM) < 0) 255 return -1; 256 } 257 258 /* All sub-paths were checked, now verify that the full data 259 * directory is owned by the application uid 260 */ 261 if (check_directory_ownership(dataPath, uid) < 0) 262 return -1; 263 264 /* all clear */ 265 return 0; 266 } 267 268 /* Return TRUE iff a character is a space or tab */ 269 static inline int 270 is_space(char c) 271 { 272 return (c == ' ' || c == '\t'); 273 } 274 275 /* Skip any space or tab character from 'p' until 'end' is reached. 276 * Return new position. 277 */ 278 static const char* 279 skip_spaces(const char* p, const char* end) 280 { 281 while (p < end && is_space(*p)) 282 p++; 283 284 return p; 285 } 286 287 /* Skip any non-space and non-tab character from 'p' until 'end'. 288 * Return new position. 289 */ 290 static const char* 291 skip_non_spaces(const char* p, const char* end) 292 { 293 while (p < end && !is_space(*p)) 294 p++; 295 296 return p; 297 } 298 299 /* Find the first occurence of 'ch' between 'p' and 'end' 300 * Return its position, or 'end' if none is found. 301 */ 302 static const char* 303 find_first(const char* p, const char* end, char ch) 304 { 305 while (p < end && *p != ch) 306 p++; 307 308 return p; 309 } 310 311 /* Check that the non-space string starting at 'p' and eventually 312 * ending at 'end' equals 'name'. Return new position (after name) 313 * on success, or NULL on failure. 314 * 315 * This function fails is 'name' is NULL, empty or contains any space. 316 */ 317 static const char* 318 compare_name(const char* p, const char* end, const char* name) 319 { 320 /* 'name' must not be NULL or empty */ 321 if (name == NULL || name[0] == '\0' || p == end) 322 return NULL; 323 324 /* compare characters to those in 'name', excluding spaces */ 325 while (*name) { 326 /* note, we don't check for *p == '\0' since 327 * it will be caught in the next conditional. 328 */ 329 if (p >= end || is_space(*p)) 330 goto BAD; 331 332 if (*p != *name) 333 goto BAD; 334 335 p++; 336 name++; 337 } 338 339 /* must be followed by end of line or space */ 340 if (p < end && !is_space(*p)) 341 goto BAD; 342 343 return p; 344 345 BAD: 346 return NULL; 347 } 348 349 /* Parse one or more whitespace characters starting from '*pp' 350 * until 'end' is reached. Updates '*pp' on exit. 351 * 352 * Return 0 on success, -1 on failure. 353 */ 354 static int 355 parse_spaces(const char** pp, const char* end) 356 { 357 const char* p = *pp; 358 359 if (p >= end || !is_space(*p)) { 360 errno = EINVAL; 361 return -1; 362 } 363 p = skip_spaces(p, end); 364 *pp = p; 365 return 0; 366 } 367 368 /* Parse a positive decimal number starting from '*pp' until 'end' 369 * is reached. Adjust '*pp' on exit. Return decimal value or -1 370 * in case of error. 371 * 372 * If the value is larger than INT_MAX, -1 will be returned, 373 * and errno set to EOVERFLOW. 374 * 375 * If '*pp' does not start with a decimal digit, -1 is returned 376 * and errno set to EINVAL. 377 */ 378 static int 379 parse_positive_decimal(const char** pp, const char* end) 380 { 381 const char* p = *pp; 382 int value = 0; 383 int overflow = 0; 384 385 if (p >= end || *p < '0' || *p > '9') { 386 errno = EINVAL; 387 return -1; 388 } 389 390 while (p < end) { 391 int ch = *p; 392 unsigned d = (unsigned)(ch - '0'); 393 int val2; 394 395 if (d >= 10U) /* d is unsigned, no lower bound check */ 396 break; 397 398 val2 = value*10 + (int)d; 399 if (val2 < value) 400 overflow = 1; 401 value = val2; 402 p++; 403 } 404 *pp = p; 405 406 if (overflow) { 407 errno = EOVERFLOW; 408 value = -1; 409 } 410 return value; 411 412 BAD: 413 *pp = p; 414 return -1; 415 } 416 417 /* Read the system's package database and extract information about 418 * 'pkgname'. Return 0 in case of success, or -1 in case of error. 419 * 420 * If the package is unknown, return -1 and set errno to ENOENT 421 * If the package database is corrupted, return -1 and set errno to EINVAL 422 */ 423 int 424 get_package_info(const char* pkgName, PackageInfo *info) 425 { 426 char* buffer; 427 size_t buffer_len; 428 const char* p; 429 const char* buffer_end; 430 int result = -1; 431 432 info->uid = 0; 433 info->isDebuggable = 0; 434 info->dataDir[0] = '\0'; 435 info->seinfo[0] = '\0'; 436 437 buffer = map_file(PACKAGES_LIST_FILE, &buffer_len); 438 if (buffer == NULL) 439 return -1; 440 441 p = buffer; 442 buffer_end = buffer + buffer_len; 443 444 /* expect the following format on each line of the control file: 445 * 446 * <pkgName> <uid> <debugFlag> <dataDir> <seinfo> 447 * 448 * where: 449 * <pkgName> is the package's name 450 * <uid> is the application-specific user Id (decimal) 451 * <debugFlag> is 1 if the package is debuggable, or 0 otherwise 452 * <dataDir> is the path to the package's data directory (e.g. /data/data/com.example.foo) 453 * <seinfo> is the seinfo label associated with the package 454 * 455 * The file is generated in com.android.server.PackageManagerService.Settings.writeLP() 456 */ 457 458 while (p < buffer_end) { 459 /* find end of current line and start of next one */ 460 const char* end = find_first(p, buffer_end, '\n'); 461 const char* next = (end < buffer_end) ? end + 1 : buffer_end; 462 const char* q; 463 int uid, debugFlag; 464 465 /* first field is the package name */ 466 p = compare_name(p, end, pkgName); 467 if (p == NULL) 468 goto NEXT_LINE; 469 470 /* skip spaces */ 471 if (parse_spaces(&p, end) < 0) 472 goto BAD_FORMAT; 473 474 /* second field is the pid */ 475 uid = parse_positive_decimal(&p, end); 476 if (uid < 0) 477 return -1; 478 479 info->uid = (uid_t) uid; 480 481 /* skip spaces */ 482 if (parse_spaces(&p, end) < 0) 483 goto BAD_FORMAT; 484 485 /* third field is debug flag (0 or 1) */ 486 debugFlag = parse_positive_decimal(&p, end); 487 switch (debugFlag) { 488 case 0: 489 info->isDebuggable = 0; 490 break; 491 case 1: 492 info->isDebuggable = 1; 493 break; 494 default: 495 goto BAD_FORMAT; 496 } 497 498 /* skip spaces */ 499 if (parse_spaces(&p, end) < 0) 500 goto BAD_FORMAT; 501 502 /* fourth field is data directory path and must not contain 503 * spaces. 504 */ 505 q = skip_non_spaces(p, end); 506 if (q == p) 507 goto BAD_FORMAT; 508 509 p = string_copy(info->dataDir, sizeof info->dataDir, p, q - p); 510 511 /* skip spaces */ 512 if (parse_spaces(&p, end) < 0) 513 goto BAD_FORMAT; 514 515 /* fifth field is the seinfo string */ 516 q = skip_non_spaces(p, end); 517 if (q == p) 518 goto BAD_FORMAT; 519 520 string_copy(info->seinfo, sizeof info->seinfo, p, q - p); 521 522 /* Ignore the rest */ 523 result = 0; 524 goto EXIT; 525 526 NEXT_LINE: 527 p = next; 528 } 529 530 /* the package is unknown */ 531 errno = ENOENT; 532 result = -1; 533 goto EXIT; 534 535 BAD_FORMAT: 536 errno = EINVAL; 537 result = -1; 538 539 EXIT: 540 unmap_file(buffer, buffer_len); 541 return result; 542 } 543