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