From 5792ce79cc79cd0eef9fadd6351521b128b4e85c Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Sat, 27 Aug 2011 18:48:45 +0200 Subject: run-as: use mmap to read package list file This patch uses mmap() to read /data/system/packages.list This avoids depending on the size of a fixed static buffer which may happen to be too short for systems with a lot of packages installed. Also avoids calling malloc() which we don't want to trust here since run-as is a setuid program. Change-Id: I1d640a08b5d73af2fc80546b01c8d970c7f6b514 --- run-as/package.c | 91 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 32 deletions(-) (limited to 'run-as') diff --git a/run-as/package.c b/run-as/package.c index ca08436..8f11646 100644 --- a/run-as/package.c +++ b/run-as/package.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "package.h" @@ -43,9 +44,6 @@ /* The file containing the list of installed packages on the system */ #define PACKAGES_LIST_FILE "/data/system/packages.list" -/* This should be large enough to hold the content of the package database file */ -#define PACKAGES_LIST_BUFFER_SIZE 65536 - /* Copy 'srclen' string bytes from 'src' into buffer 'dst' of size 'dstlen' * This function always zero-terminate the destination buffer unless * 'dstlen' is 0, even in case of overflow. @@ -67,40 +65,63 @@ string_copy(char* dst, size_t dstlen, const char* src, size_t srclen) *dst = '\0'; /* zero-terminate result */ } -/* Read up to 'buffsize' bytes into 'buff' from the file - * named 'filename'. Return byte length on success, or -1 - * on error. +/* Open 'filename' and map it into our address-space. + * Returns buffer address, or NULL on error + * On exit, *filesize will be set to the file's size, or 0 on error */ -static int -read_file(const char* filename, char* buff, size_t buffsize) +static void* +map_file(const char* filename, size_t* filesize) { - int fd, len, old_errno; + int fd, ret, old_errno; + struct stat st; + size_t length = 0; + void* address = NULL; - /* check the input buffer size */ - if (buffsize >= INT_MAX) { - errno = EINVAL; - return -1; - } + *filesize = 0; /* open the file for reading */ - do { - fd = open(filename, O_RDONLY); - } while (fd < 0 && errno == EINTR); - + fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY)); if (fd < 0) - return -1; + return NULL; - /* read the content */ - do { - len = read(fd, buff, buffsize); - } while (len < 0 && errno == EINTR); + /* get its size */ + ret = TEMP_FAILURE_RETRY(fstat(fd, &st)); + if (ret < 0) + goto EXIT; + + /* Ensure that the size is not ridiculously large */ + length = (size_t)st.st_size; + if ((off_t)length != st.st_size) { + errno = ENOMEM; + goto EXIT; + } + + /* Memory-map the file now */ + address = TEMP_FAILURE_RETRY(mmap(NULL, length, PROT_READ, MAP_PRIVATE, fd, 0)); + if (address == MAP_FAILED) { + address = NULL; + goto EXIT; + } + /* We're good, return size */ + *filesize = length; + +EXIT: /* close the file, preserve old errno for better diagnostics */ old_errno = errno; close(fd); errno = old_errno; - return len; + return address; +} + +/* unmap the file, but preserve errno */ +static void +unmap_file(void* address, size_t size) +{ + int old_errno = errno; + TEMP_FAILURE_RETRY(munmap(address, size)); + errno = old_errno; } /* Check that a given directory: @@ -371,18 +392,18 @@ BAD: int get_package_info(const char* pkgName, PackageInfo *info) { - static char buffer[PACKAGES_LIST_BUFFER_SIZE]; - int buffer_len; + char* buffer; + size_t buffer_len; const char* p; const char* buffer_end; - int result; + int result = -1; info->uid = 0; info->isDebuggable = 0; info->dataDir[0] = '\0'; - buffer_len = read_file(PACKAGES_LIST_FILE, buffer, sizeof buffer); - if (buffer_len < 0) + buffer = map_file(PACKAGES_LIST_FILE, &buffer_len); + if (buffer == NULL) return -1; p = buffer; @@ -455,7 +476,8 @@ get_package_info(const char* pkgName, PackageInfo *info) string_copy(info->dataDir, sizeof info->dataDir, p, q - p); /* Ignore the rest */ - return 0; + result = 0; + goto EXIT; NEXT_LINE: p = next; @@ -463,9 +485,14 @@ get_package_info(const char* pkgName, PackageInfo *info) /* the package is unknown */ errno = ENOENT; - return -1; + result = -1; + goto EXIT; BAD_FORMAT: errno = EINVAL; - return -1; + result = -1; + +EXIT: + unmap_file(buffer, buffer_len); + return result; } -- cgit v1.1