am a1a22b57: am e67b5848: am 4956c0fe: am 5b85b1d4: libutils: fix overflow in String8::allocFromUTF8 * commit 'a1a22b5736d5ad71531fd07d5c4103585e8e8977': libutils: fix overflow in String8::allocFromUTF8
diff --git a/adb/Android.mk b/adb/Android.mk index af7d7e5..b70c153 100644 --- a/adb/Android.mk +++ b/adb/Android.mk
@@ -111,6 +111,7 @@ jdwp_service.c \ framebuffer_service.c \ remount_service.c \ + disable_verity_service.c \ usb_linux_client.c LOCAL_CFLAGS := -O2 -g -DADB_HOST=0 -Wall -Wno-unused-parameter -Werror @@ -120,13 +121,25 @@ LOCAL_CFLAGS += -DALLOW_ADBD_ROOT=1 endif +ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT))) +LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1 +endif + LOCAL_MODULE := adbd LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN) LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED) +LOCAL_C_INCLUDES += system/extras/ext4_utils system/core/fs_mgr/include -LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt libselinux +LOCAL_STATIC_LIBRARIES := liblog \ + libfs_mgr \ + libcutils \ + libc \ + libmincrypt \ + libselinux \ + libext4_utils_static + include $(BUILD_EXECUTABLE)
diff --git a/adb/adb.h b/adb/adb.h index 4f06800..44e5981 100644 --- a/adb/adb.h +++ b/adb/adb.h
@@ -329,6 +329,7 @@ #if !ADB_HOST void framebuffer_service(int fd, void *cookie); void remount_service(int fd, void *cookie); +void disable_verity_service(int fd, void* cookie); #endif /* packet allocator */
diff --git a/adb/adb_auth.h b/adb/adb_auth.h index b24c674..54dd537 100644 --- a/adb/adb_auth.h +++ b/adb/adb_auth.h
@@ -18,6 +18,7 @@ #define __ADB_AUTH_H void adb_auth_init(void); +int adb_auth_keygen(const char* filename); void adb_auth_verified(atransport *t); void send_auth_request(atransport *t);
diff --git a/adb/adb_auth_host.c b/adb/adb_auth_host.c index 783774a..dd83900 100644 --- a/adb/adb_auth_host.c +++ b/adb/adb_auth_host.c
@@ -15,9 +15,12 @@ */ #include <stdio.h> +#include <stdlib.h> #ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include "windows.h" # include "shlobj.h" #else @@ -110,18 +113,34 @@ static void get_user_info(char *buf, size_t len) { char hostname[1024], username[1024]; - int ret; + int ret = -1; + + if (getenv("HOSTNAME") != NULL) { + strncpy(hostname, getenv("HOSTNAME"), sizeof(hostname)); + hostname[sizeof(hostname)-1] = '\0'; + ret = 0; + } #ifndef _WIN32 - ret = gethostname(hostname, sizeof(hostname)); if (ret < 0) + ret = gethostname(hostname, sizeof(hostname)); #endif + if (ret < 0) strcpy(hostname, "unknown"); + ret = -1; + + if (getenv("LOGNAME") != NULL) { + strncpy(username, getenv("LOGNAME"), sizeof(username)); + username[sizeof(username)-1] = '\0'; + ret = 0; + } + #if !defined _WIN32 && !defined ADB_HOST_ON_TARGET - ret = getlogin_r(username, sizeof(username)); if (ret < 0) + ret = getlogin_r(username, sizeof(username)); #endif + if (ret < 0) strcpy(username, "unknown"); ret = snprintf(buf, len, " %s@%s", username, hostname); @@ -408,6 +427,11 @@ return ret + 1; } +int adb_auth_keygen(const char* filename) { + adb_trace_mask |= (1 << TRACE_AUTH); + return (generate_key(filename) == 0); +} + void adb_auth_init(void) { int ret;
diff --git a/adb/commandline.c b/adb/commandline.c index 05b4ef6..7704878 100644 --- a/adb/commandline.c +++ b/adb/commandline.c
@@ -36,6 +36,7 @@ #define TRACE_TAG TRACE_ADB #include "adb.h" #include "adb_client.h" +#include "adb_auth.h" #include "file_sync_service.h" static int do_cmd(transport_type ttype, char* serial, char *cmd, ...); @@ -189,6 +190,10 @@ "\n" " adb restore <file> - restore device contents from the <file> backup archive\n" "\n" + " adb disable-verity - disable dm-verity checking on USERDEBUG builds\n" + " adb keygen <file> - generate adb public/private key. The private key is stored in <file>,\n" + " and the public key is stored in <file>.pub. Any existing files\n" + " are overwritten.\n" " adb help - show this help message\n" " adb version - show version num\n" "\n" @@ -205,8 +210,7 @@ " adb reboot-bootloader - reboots the device into the bootloader\n" " adb root - restarts the adbd daemon with root permissions\n" " adb usb - restarts the adbd daemon listening on USB\n" - " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port" - "\n" + " adb tcpip <port> - restarts the adbd daemon listening on TCP on the specified port\n" "networking:\n" " adb ppp <tty> [parameters] - Run PPP over USB.\n" " Note: you should not automatically start a PPP connection.\n" @@ -1437,7 +1441,7 @@ if(!strcmp(argv[0], "remount") || !strcmp(argv[0], "reboot") || !strcmp(argv[0], "reboot-bootloader") || !strcmp(argv[0], "tcpip") || !strcmp(argv[0], "usb") - || !strcmp(argv[0], "root")) { + || !strcmp(argv[0], "root") || !strcmp(argv[0], "disable-verity")) { char command[100]; if (!strcmp(argv[0], "reboot-bootloader")) snprintf(command, sizeof(command), "reboot:bootloader"); @@ -1720,6 +1724,11 @@ return restore(argc, argv); } + if (!strcmp(argv[0], "keygen")) { + if (argc < 2) return usage(); + return adb_auth_keygen(argv[1]); + } + if (!strcmp(argv[0], "jdwp")) { int fd = adb_connect("jdwp"); if (fd >= 0) {
diff --git a/adb/disable_verity_service.c b/adb/disable_verity_service.c new file mode 100644 index 0000000..ed3da52 --- /dev/null +++ b/adb/disable_verity_service.c
@@ -0,0 +1,199 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sysdeps.h" + +#define TRACE_TAG TRACE_ADB +#include "adb.h" + +#include <stdio.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <inttypes.h> + +#include "cutils/properties.h" +#include "ext4_sb.h" +#include <fs_mgr.h> + +#define FSTAB_PREFIX "/fstab." +struct fstab *fstab; + +__attribute__((__format__(printf, 2, 3))) __nonnull((2)) +static void write_console(int fd, const char* format, ...) +{ + char buffer[256]; + va_list args; + va_start (args, format); + vsnprintf (buffer, sizeof(buffer), format, args); + va_end (args); + + adb_write(fd, buffer, strnlen(buffer, sizeof(buffer))); +} + +static int get_target_device_size(int fd, const char *blk_device, + uint64_t *device_size) +{ + int data_device; + struct ext4_super_block sb; + struct fs_info info; + + info.len = 0; /* Only len is set to 0 to ask the device for real size. */ + + data_device = adb_open(blk_device, O_RDONLY | O_CLOEXEC); + if (data_device < 0) { + write_console(fd, "Error opening block device (%s)\n", strerror(errno)); + return -1; + } + + if (lseek64(data_device, 1024, SEEK_SET) < 0) { + write_console(fd, "Error seeking to superblock\n"); + adb_close(data_device); + return -1; + } + + if (adb_read(data_device, &sb, sizeof(sb)) != sizeof(sb)) { + write_console(fd, "Error reading superblock\n"); + adb_close(data_device); + return -1; + } + + ext4_parse_sb(&sb, &info); + *device_size = info.len; + + adb_close(data_device); + return 0; +} + +static int disable_verity(int fd, const char *block_device, + const char* mount_point) +{ + uint32_t magic_number; + const uint32_t voff = VERITY_METADATA_MAGIC_DISABLE; + uint64_t device_length; + int device; + int retval = -1; + + device = adb_open(block_device, O_RDWR | O_CLOEXEC); + if (device == -1) { + write_console(fd, "Could not open block device %s (%s).\n", + block_device, strerror(errno)); + write_console(fd, "Maybe run adb remount?\n"); + goto errout; + } + + // find the start of the verity metadata + if (get_target_device_size(fd, (char*)block_device, &device_length) < 0) { + write_console(fd, "Could not get target device size.\n"); + goto errout; + } + + if (lseek64(device, device_length, SEEK_SET) < 0) { + write_console(fd, + "Could not seek to start of verity metadata block.\n"); + goto errout; + } + + // check the magic number + if (adb_read(device, &magic_number, sizeof(magic_number)) + != sizeof(magic_number)) { + write_console(fd, "Couldn't read magic number!\n"); + goto errout; + } + + if (magic_number == VERITY_METADATA_MAGIC_DISABLE) { + write_console(fd, "Verity already disabled on %s\n", mount_point); + goto errout; + } + + if (magic_number != VERITY_METADATA_MAGIC_NUMBER) { + write_console(fd, + "Couldn't find verity metadata at offset %"PRIu64"!\n", + device_length); + goto errout; + } + + if (lseek64(device, device_length, SEEK_SET) < 0) { + write_console(fd, + "Could not seek to start of verity metadata block.\n"); + goto errout; + } + + if (adb_write(device, &voff, sizeof(voff)) != sizeof(voff)) { + write_console(fd, "Could not set verity disabled flag on device %s\n", + block_device); + goto errout; + } + + write_console(fd, "Verity disabled on %s\n", mount_point); + retval = 0; +errout: + if (device != -1) + adb_close(device); + return retval; +} + +void disable_verity_service(int fd, void* cookie) +{ +#ifdef ALLOW_ADBD_DISABLE_VERITY + char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)]; + char propbuf[PROPERTY_VALUE_MAX]; + int i; + bool any_disabled = false; + + property_get("ro.secure", propbuf, "0"); + if (strcmp(propbuf, "1")) { + write_console(fd, "verity not enabled - ENG build\n"); + goto errout; + } + + property_get("ro.debuggable", propbuf, "0"); + if (strcmp(propbuf, "1")) { + write_console(fd, "verity cannot be disabled - USER build\n"); + goto errout; + } + + property_get("ro.hardware", propbuf, ""); + snprintf(fstab_filename, sizeof(fstab_filename), FSTAB_PREFIX"%s", propbuf); + + fstab = fs_mgr_read_fstab(fstab_filename); + if (!fstab) { + write_console(fd, "Failed to open %s\nMaybe run adb root?\n", + fstab_filename); + goto errout; + } + + /* Loop through entries looking for ones that vold manages */ + for (i = 0; i < fstab->num_entries; i++) { + if(fs_mgr_is_verified(&fstab->recs[i])) { + if (!disable_verity(fd, fstab->recs[i].blk_device, + fstab->recs[i].mount_point)) { + any_disabled = true; + } + } + } + + if (any_disabled) { + write_console(fd, + "Now reboot your device for settings to take effect\n"); + } +#else + write_console(fd, "disable-verity only works for userdebug builds\n"); +#endif + +errout: + adb_close(fd); +}
diff --git a/adb/get_my_path_darwin.c b/adb/get_my_path_darwin.c index 5b95d15..ff1396c 100644 --- a/adb/get_my_path_darwin.c +++ b/adb/get_my_path_darwin.c
@@ -19,12 +19,12 @@ void get_my_path(char *s, size_t maxLen) { - ProcessSerialNumber psn; - GetCurrentProcess(&psn); - CFDictionaryRef dict; - dict = ProcessInformationCopyDictionary(&psn, 0xffffffff); - CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict, - CFSTR("CFBundleExecutable")); - CFStringGetCString(value, s, maxLen, kCFStringEncodingUTF8); + CFBundleRef mainBundle = CFBundleGetMainBundle(); + CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle); + CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle); + CFRelease(executableURL); + + CFStringGetFileSystemRepresentation(executablePathString, s, maxLen); + CFRelease(executablePathString); }
diff --git a/adb/remount_service.c b/adb/remount_service.c index 72d15a1..36367a7 100644 --- a/adb/remount_service.c +++ b/adb/remount_service.c
@@ -14,6 +14,8 @@ * limitations under the License. */ +#include "sysdeps.h" + #include <errno.h> #include <fcntl.h> #include <stdio.h> @@ -22,7 +24,7 @@ #include <sys/mount.h> #include <unistd.h> -#include "sysdeps.h" +#include "cutils/properties.h" #define TRACE_TAG TRACE_ADB #include "adb.h" @@ -115,6 +117,36 @@ void remount_service(int fd, void *cookie) { char buffer[200]; + char prop_buf[PROPERTY_VALUE_MAX]; + + bool system_verified = false, vendor_verified = false; + property_get("partition.system.verified", prop_buf, "0"); + if (!strcmp(prop_buf, "1")) { + system_verified = true; + } + + property_get("partition.vendor.verified", prop_buf, "0"); + if (!strcmp(prop_buf, "1")) { + vendor_verified = true; + } + + if (system_verified || vendor_verified) { + // Allow remount but warn of likely bad effects + bool both = system_verified && vendor_verified; + snprintf(buffer, sizeof(buffer), + "dm_verity is enabled on the %s%s%s partition%s.\n", + system_verified ? "system" : "", + both ? " and " : "", + vendor_verified ? "vendor" : "", + both ? "s" : ""); + write_string(fd, buffer); + snprintf(buffer, sizeof(buffer), + "Use \"adb disable-verity\" to disable verity.\n" + "If you do not, remount may succeed, however, you will still " + "not be able to write to these volumes.\n"); + write_string(fd, buffer); + } + if (remount("/system", &system_ro)) { snprintf(buffer, sizeof(buffer), "remount of system failed: %s\n",strerror(errno)); write_string(fd, buffer);
diff --git a/adb/services.c b/adb/services.c index e61371a..21b08dc 100644 --- a/adb/services.c +++ b/adb/services.c
@@ -469,6 +469,8 @@ free(cookie); } } + } else if(!strncmp(name, "disable-verity:", 15)) { + ret = create_service_thread(disable_verity_service, NULL); #endif } if (ret >= 0) {
diff --git a/adb/sysdeps_win32.c b/adb/sysdeps_win32.c index b082c6d..e69ec2b 100644 --- a/adb/sysdeps_win32.c +++ b/adb/sysdeps_win32.c
@@ -2,6 +2,7 @@ #include <winsock2.h> #include <windows.h> #include <stdio.h> +#include <stdlib.h> #include <errno.h> #define TRACE_TAG TRACE_SYSDEPS #include "adb.h"
diff --git a/adb/usb_vendors.c b/adb/usb_vendors.c index 957e5db..19bcae4 100755 --- a/adb/usb_vendors.c +++ b/adb/usb_vendors.c
@@ -17,9 +17,12 @@ #include "usb_vendors.h" #include <stdio.h> +#include <stdlib.h> #ifdef _WIN32 -# define WIN32_LEAN_AND_MEAN +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include "windows.h" # include "shlobj.h" #else
diff --git a/adb/usb_windows.c b/adb/usb_windows.c index b7ad913..a2d7226 100644 --- a/adb/usb_windows.c +++ b/adb/usb_windows.c
@@ -21,6 +21,7 @@ #include <usb100.h> #include <adb_api.h> #include <stdio.h> +#include <stdlib.h> #include "sysdeps.h"
diff --git a/debuggerd/backtrace.cpp b/debuggerd/backtrace.cpp index e49ef9b..c2a1dbc 100644 --- a/debuggerd/backtrace.cpp +++ b/debuggerd/backtrace.cpp
@@ -88,7 +88,9 @@ return; } - wait_for_stop(tid, total_sleep_time_usec); + if (!attached && wait_for_sigstop(tid, total_sleep_time_usec, detach_failed) == -1) { + return; + } UniquePtr<Backtrace> backtrace(Backtrace::Create(tid, BACKTRACE_CURRENT_THREAD)); if (backtrace->Unwind(0)) {
diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp index 61805c9..06c16f8 100644 --- a/debuggerd/debuggerd.cpp +++ b/debuggerd/debuggerd.cpp
@@ -77,7 +77,7 @@ "*\n" "* Wait for gdb to start, then press the VOLUME DOWN key\n" "* to let the process continue crashing.\n" - "********************************************************\n", + "********************************************************", request.pid, exe, request.tid); // Wait for VOLUME DOWN. @@ -129,11 +129,11 @@ socklen_t len = sizeof(cr); int status = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cr, &len); if (status != 0) { - ALOGE("cannot get credentials\n"); + ALOGE("cannot get credentials"); return -1; } - ALOGV("reading tid\n"); + ALOGV("reading tid"); fcntl(fd, F_SETFL, O_NONBLOCK); pollfd pollfds[1]; @@ -227,6 +227,7 @@ ALOGE("ptrace attach failed: %s\n", strerror(errno)); } else { bool detach_failed = false; + bool tid_unresponsive = false; bool attach_gdb = should_attach_gdb(&request); if (TEMP_FAILURE_RETRY(write(fd, "\0", 1)) != 1) { ALOGE("failed responding to client: %s\n", strerror(errno)); @@ -240,8 +241,9 @@ int total_sleep_time_usec = 0; for (;;) { - int signal = wait_for_signal(request.tid, &total_sleep_time_usec); - if (signal < 0) { + int signal = wait_for_sigstop(request.tid, &total_sleep_time_usec, &detach_failed); + if (signal == -1) { + tid_unresponsive = true; break; } @@ -308,27 +310,21 @@ free(tombstone_path); } - ALOGV("detaching\n"); - if (attach_gdb) { - // stop the process so we can debug - kill(request.pid, SIGSTOP); - - // detach so we can attach gdbserver - if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) { - ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno)); - detach_failed = true; + if (!tid_unresponsive) { + ALOGV("detaching"); + if (attach_gdb) { + // stop the process so we can debug + kill(request.pid, SIGSTOP); } - - // if debug.db.uid is set, its value indicates if we should wait - // for user action for the crashing process. - // in this case, we log a message and turn the debug LED on - // waiting for a gdb connection (for instance) - wait_for_user_action(request); - } else { - // just detach if (ptrace(PTRACE_DETACH, request.tid, 0, 0)) { - ALOGE("ptrace detach from %d failed: %s\n", request.tid, strerror(errno)); + ALOGE("ptrace detach from %d failed: %s", request.tid, strerror(errno)); detach_failed = true; + } else if (attach_gdb) { + // if debug.db.uid is set, its value indicates if we should wait + // for user action for the crashing process. + // in this case, we log a message and turn the debug LED on + // waiting for a gdb connection (for instance) + wait_for_user_action(request); } }
diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp index a7e1524..0c1b80f 100644 --- a/debuggerd/tombstone.cpp +++ b/debuggerd/tombstone.cpp
@@ -374,11 +374,7 @@ } } -static void dump_thread( - Backtrace* backtrace, log_t* log, int* total_sleep_time_usec) { - - wait_for_stop(backtrace->Tid(), total_sleep_time_usec); - +static void dump_thread(Backtrace* backtrace, log_t* log) { dump_registers(log, backtrace->Tid()); dump_backtrace_and_stack(backtrace, log); @@ -421,13 +417,17 @@ continue; } + if (wait_for_sigstop(new_tid, total_sleep_time_usec, &detach_failed) == -1) { + continue; + } + log->current_tid = new_tid; _LOG(log, logtype::THREAD, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n"); dump_thread_info(log, pid, new_tid); UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map)); if (backtrace->Unwind(0)) { - dump_thread(backtrace.get(), log, total_sleep_time_usec); + dump_thread(backtrace.get(), log); } log->current_tid = log->crashed_tid; @@ -628,7 +628,7 @@ UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map.get())); if (backtrace->Unwind(0)) { dump_abort_message(backtrace.get(), log, abort_msg_address); - dump_thread(backtrace.get(), log, total_sleep_time_usec); + dump_thread(backtrace.get(), log); } if (want_logs) {
diff --git a/debuggerd/utility.cpp b/debuggerd/utility.cpp index 9a30fe3..2baf9de 100644 --- a/debuggerd/utility.cpp +++ b/debuggerd/utility.cpp
@@ -28,8 +28,8 @@ #include <backtrace/Backtrace.h> #include <log/log.h> -const int sleep_time_usec = 50000; // 0.05 seconds -const int max_total_sleep_usec = 10000000; // 10 seconds +const int SLEEP_TIME_USEC = 50000; // 0.05 seconds +const int MAX_TOTAL_SLEEP_USEC = 10000000; // 10 seconds static int write_to_am(int fd, const char* buf, int len) { int to_write = len; @@ -91,48 +91,44 @@ } } -int wait_for_signal(pid_t tid, int* total_sleep_time_usec) { +int wait_for_sigstop(pid_t tid, int* total_sleep_time_usec, bool* detach_failed) { + bool allow_dead_tid = false; for (;;) { int status; - pid_t n = waitpid(tid, &status, __WALL | WNOHANG); - if (n < 0) { - if (errno == EAGAIN) - continue; - ALOGE("waitpid failed: %s\n", strerror(errno)); - return -1; - } else if (n > 0) { - ALOGV("waitpid: n=%d status=%08x\n", n, status); + pid_t n = TEMP_FAILURE_RETRY(waitpid(tid, &status, __WALL | WNOHANG)); + if (n == -1) { + ALOGE("waitpid failed: tid %d, %s", tid, strerror(errno)); + break; + } else if (n == tid) { if (WIFSTOPPED(status)) { return WSTOPSIG(status); } else { ALOGE("unexpected waitpid response: n=%d, status=%08x\n", n, status); - return -1; + // This is the only circumstance under which we can allow a detach + // to fail with ESRCH, which indicates the tid has exited. + allow_dead_tid = true; + break; } } - if (*total_sleep_time_usec > max_total_sleep_usec) { - ALOGE("timed out waiting for tid=%d to die\n", tid); - return -1; - } - - // not ready yet - ALOGV("not ready yet\n"); - usleep(sleep_time_usec); - *total_sleep_time_usec += sleep_time_usec; - } -} - -void wait_for_stop(pid_t tid, int* total_sleep_time_usec) { - siginfo_t si; - while (TEMP_FAILURE_RETRY(ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) < 0 && errno == ESRCH) { - if (*total_sleep_time_usec > max_total_sleep_usec) { - ALOGE("timed out waiting for tid=%d to stop\n", tid); + if (*total_sleep_time_usec > MAX_TOTAL_SLEEP_USEC) { + ALOGE("timed out waiting for stop signal: tid=%d", tid); break; } - usleep(sleep_time_usec); - *total_sleep_time_usec += sleep_time_usec; + usleep(SLEEP_TIME_USEC); + *total_sleep_time_usec += SLEEP_TIME_USEC; } + + if (ptrace(PTRACE_DETACH, tid, 0, 0) != 0) { + if (allow_dead_tid && errno == ESRCH) { + ALOGE("tid exited before attach completed: tid %d", tid); + } else { + *detach_failed = true; + ALOGE("detach failed: tid %d, %s", tid, strerror(errno)); + } + } + return -1; } #if defined (__mips__)
diff --git a/debuggerd/utility.h b/debuggerd/utility.h index 82413b8..58a882c 100644 --- a/debuggerd/utility.h +++ b/debuggerd/utility.h
@@ -67,12 +67,11 @@ LOGS }; -/* Log information onto the tombstone. */ +// Log information onto the tombstone. void _LOG(log_t* log, logtype ltype, const char *fmt, ...) __attribute__ ((format(printf, 3, 4))); -int wait_for_signal(pid_t tid, int* total_sleep_time_usec); -void wait_for_stop(pid_t tid, int* total_sleep_time_usec); +int wait_for_sigstop(pid_t, int*, bool*); void dump_memory(log_t* log, pid_t tid, uintptr_t addr);
diff --git a/fastboot/usb_windows.c b/fastboot/usb_windows.c index 0d13863..a09610f 100644 --- a/fastboot/usb_windows.c +++ b/fastboot/usb_windows.c
@@ -32,6 +32,7 @@ #include <usb100.h> #include <adb_api.h> #include <stdio.h> +#include <stdlib.h> #include "usb.h"
diff --git a/fastboot/util_osx.c b/fastboot/util_osx.c index 26b832a..e718562 100644 --- a/fastboot/util_osx.c +++ b/fastboot/util_osx.c
@@ -31,14 +31,15 @@ void get_my_path(char s[PATH_MAX]) { - char *x; - ProcessSerialNumber psn; - GetCurrentProcess(&psn); - CFDictionaryRef dict; - dict = ProcessInformationCopyDictionary(&psn, 0xffffffff); - CFStringRef value = (CFStringRef)CFDictionaryGetValue(dict, - CFSTR("CFBundleExecutable")); - CFStringGetCString(value, s, PATH_MAX - 1, kCFStringEncodingUTF8); + CFBundleRef mainBundle = CFBundleGetMainBundle(); + CFURLRef executableURL = CFBundleCopyExecutableURL(mainBundle); + CFStringRef executablePathString = CFURLCopyFileSystemPath(executableURL, kCFURLPOSIXPathStyle); + CFRelease(executableURL); + + CFStringGetFileSystemRepresentation(executablePathString, s, PATH_MAX-1); + CFRelease(executablePathString); + + char *x; x = strrchr(s, '/'); if(x) x[1] = 0; }
diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk index 7cffc37..0ec6c4b 100644 --- a/fs_mgr/Android.mk +++ b/fs_mgr/Android.mk
@@ -4,8 +4,12 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= fs_mgr.c fs_mgr_verity.c fs_mgr_fstab.c +LOCAL_SRC_FILES += fs_mgr_format.c -LOCAL_C_INCLUDES := $(LOCAL_PATH)/include +LOCAL_C_INCLUDES := $(LOCAL_PATH)/include \ + system/vold \ + system/extras/ext4_utils \ + external/openssl/include LOCAL_MODULE:= libfs_mgr LOCAL_STATIC_LIBRARIES := liblogwrap libmincrypt libext4_utils_static @@ -13,6 +17,10 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include LOCAL_CFLAGS := -Werror +ifneq (,$(filter userdebug,$(TARGET_BUILD_VARIANT))) +LOCAL_CFLAGS += -DALLOW_ADBD_DISABLE_VERITY=1 +endif + include $(BUILD_STATIC_LIBRARY) @@ -31,6 +39,7 @@ LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_UNSTRIPPED) LOCAL_STATIC_LIBRARIES := libfs_mgr liblogwrap libcutils liblog libc libmincrypt libext4_utils_static +LOCAL_STATIC_LIBRARIES += libsparse_static libz libselinux LOCAL_CFLAGS := -Werror
diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c index 91e6c33..8533ff6 100644 --- a/fs_mgr/fs_mgr.c +++ b/fs_mgr/fs_mgr.c
@@ -40,6 +40,9 @@ #include "mincrypt/sha.h" #include "mincrypt/sha256.h" +#include "ext4_utils.h" +#include "wipe.h" + #include "fs_mgr_priv.h" #include "fs_mgr_priv_verity.h" @@ -141,9 +144,10 @@ } else if (!strcmp(fs_type, "f2fs")) { char *f2fs_fsck_argv[] = { F2FS_FSCK_BIN, + "-f", blk_device }; - INFO("Running %s on %s\n", F2FS_FSCK_BIN, blk_device); + INFO("Running %s -f %s\n", F2FS_FSCK_BIN, blk_device); ret = android_fork_execvp_ext(ARRAY_SIZE(f2fs_fsck_argv), f2fs_fsck_argv, &status, true, LOG_KLOG | LOG_FILE, @@ -245,6 +249,25 @@ return strcmp(value, "1") ? 0 : 1; } +static int device_is_secure() { + int ret = -1; + char value[PROP_VALUE_MAX]; + ret = __system_property_get("ro.secure", value); + /* If error, we want to fail secure */ + if (ret < 0) + return 1; + return strcmp(value, "0") ? 1 : 0; +} + +static int device_is_force_encrypted() { + int ret = -1; + char value[PROP_VALUE_MAX]; + ret = __system_property_get("ro.vold.forceencryption", value); + if (ret < 0) + return 0; + return strcmp(value, "1") ? 0 : 1; +} + /* * Tries to mount any of the consecutive fstab entries that match * the mountpoint of the one given by fstab->recs[start_idx]. @@ -350,14 +373,18 @@ wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT); } - if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && - !device_is_debuggable()) { - if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) { + if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) { + int rc = fs_mgr_setup_verity(&fstab->recs[i]); + if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) { + INFO("Verity disabled"); + } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) { ERROR("Could not set up verified partition, skipping!\n"); continue; } } int last_idx_inspected; + int top_idx = i; + mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx); i = last_idx_inspected; mount_errno = errno; @@ -365,7 +392,9 @@ /* Deal with encryptability. */ if (!mret) { /* If this is encryptable, need to trigger encryption */ - if ((fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT)) { + if ( (fstab->recs[attempted_idx].fs_mgr_flags & MF_FORCECRYPT) + || (device_is_force_encrypted() + && fs_mgr_is_encryptable(&fstab->recs[attempted_idx]))) { if (umount(fstab->recs[attempted_idx].mount_point) == 0) { if (encryptable == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { ERROR("Will try to encrypt %s %s\n", fstab->recs[attempted_idx].mount_point, @@ -385,10 +414,38 @@ continue; } - /* mount(2) returned an error, check if it's encryptable and deal with it */ + /* mount(2) returned an error, handle the encryptable/formattable case */ + bool wiped = partition_wiped(fstab->recs[top_idx].blk_device); + if (mret && mount_errno != EBUSY && mount_errno != EACCES && + fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) { + /* top_idx and attempted_idx point at the same partition, but sometimes + * at two different lines in the fstab. Use the top one for formatting + * as that is the preferred one. + */ + ERROR("%s(): %s is wiped and %s %s is formattable. Format it.\n", __func__, + fstab->recs[top_idx].blk_device, fstab->recs[top_idx].mount_point, + fstab->recs[top_idx].fs_type); + if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) && + strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) { + int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY, 0644); + if (fd >= 0) { + INFO("%s(): also wipe %s\n", __func__, fstab->recs[top_idx].key_loc); + wipe_block_device(fd, get_file_size(fd)); + close(fd); + } else { + ERROR("%s(): %s wouldn't open (%s)\n", __func__, + fstab->recs[top_idx].key_loc, strerror(errno)); + } + } + if (fs_mgr_do_format(&fstab->recs[top_idx]) == 0) { + /* Let's replay the mount actions. */ + i = top_idx - 1; + continue; + } + } if (mret && mount_errno != EBUSY && mount_errno != EACCES && fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) { - if(partition_wiped(fstab->recs[attempted_idx].blk_device)) { + if (wiped) { ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__, fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_type); @@ -467,9 +524,11 @@ fstab->recs[i].mount_point); } - if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && - !device_is_debuggable()) { - if (fs_mgr_setup_verity(&fstab->recs[i]) < 0) { + if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) { + int rc = fs_mgr_setup_verity(&fstab->recs[i]); + if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) { + INFO("Verity disabled"); + } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) { ERROR("Could not set up verified partition, skipping!\n"); continue; }
diff --git a/fs_mgr/fs_mgr_format.c b/fs_mgr/fs_mgr_format.c new file mode 100644 index 0000000..b5b92b5 --- /dev/null +++ b/fs_mgr/fs_mgr_format.c
@@ -0,0 +1,119 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/wait.h> +#include <errno.h> +#include <cutils/partition_utils.h> +#include <sys/mount.h> +#include "ext4_utils.h" +#include "ext4.h" +#include "make_ext4fs.h" +#include "fs_mgr_priv.h" + +extern struct fs_info info; /* magic global from ext4_utils */ +extern void reset_ext4fs_info(); + +static int format_ext4(char *fs_blkdev, char *fs_mnt_point) +{ + unsigned int nr_sec; + int fd, rc = 0; + + if ((fd = open(fs_blkdev, O_WRONLY, 0644)) < 0) { + ERROR("Cannot open block device. %s\n", strerror(errno)); + return -1; + } + + if ((ioctl(fd, BLKGETSIZE, &nr_sec)) == -1) { + ERROR("Cannot get block device size. %s\n", strerror(errno)); + close(fd); + return -1; + } + + /* Format the partition using the calculated length */ + reset_ext4fs_info(); + info.len = ((off64_t)nr_sec * 512); + + /* Use make_ext4fs_internal to avoid wiping an already-wiped partition. */ + rc = make_ext4fs_internal(fd, NULL, fs_mnt_point, 0, 0, 0, 0, 0, 0, 0, 0, NULL); + if (rc) { + ERROR("make_ext4fs returned %d.\n", rc); + } + close(fd); + + return rc; +} + +static int format_f2fs(char *fs_blkdev) +{ + char * args[3]; + int pid; + int rc = 0; + + args[0] = (char *)"/sbin/mkfs.f2fs"; + args[1] = fs_blkdev; + args[2] = (char *)0; + + pid = fork(); + if (pid < 0) { + return pid; + } + if (!pid) { + /* This doesn't return */ + execv("/sbin/mkfs.f2fs", args); + exit(1); + } + for(;;) { + pid_t p = waitpid(pid, &rc, 0); + if (p != pid) { + ERROR("Error waiting for child process - %d\n", p); + rc = -1; + break; + } + if (WIFEXITED(rc)) { + rc = WEXITSTATUS(rc); + INFO("%s done, status %d\n", args[0], rc); + if (rc) { + rc = -1; + } + break; + } + ERROR("Still waiting for %s...\n", args[0]); + } + + return rc; +} + +int fs_mgr_do_format(struct fstab_rec *fstab) +{ + int rc = -EINVAL; + + ERROR("%s: Format %s as '%s'.\n", __func__, fstab->blk_device, fstab->fs_type); + + if (!strncmp(fstab->fs_type, "f2fs", 4)) { + rc = format_f2fs(fstab->blk_device); + } else if (!strncmp(fstab->fs_type, "ext4", 4)) { + rc = format_ext4(fstab->blk_device, fstab->mount_point); + } else { + ERROR("File system type '%s' is not supported\n", fstab->fs_type); + } + + return rc; +}
diff --git a/fs_mgr/fs_mgr_fstab.c b/fs_mgr/fs_mgr_fstab.c index 3f84179..c2da28a 100644 --- a/fs_mgr/fs_mgr_fstab.c +++ b/fs_mgr/fs_mgr_fstab.c
@@ -15,10 +15,12 @@ */ #include <ctype.h> +#include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/mount.h> +#include <unistd.h> #include "fs_mgr_priv.h" @@ -68,10 +70,24 @@ { "zramsize=", MF_ZRAMSIZE }, { "verify", MF_VERIFY }, { "noemulatedsd", MF_NOEMULATEDSD }, + { "formattable", MF_FORMATTABLE }, { "defaults", 0 }, { 0, 0 }, }; +static uint64_t calculate_zram_size(unsigned int percentage) +{ + uint64_t total; + + total = sysconf(_SC_PHYS_PAGES); + total *= percentage; + total /= 100; + + total *= sysconf(_SC_PAGESIZE); + + return total; +} + static int parse_flags(char *flags, struct flag_list *fl, struct fs_mgr_flag_values *flag_vals, char *fs_options, int fs_options_len) @@ -145,7 +161,12 @@ } else if ((fl[i].flag == MF_SWAPPRIO) && flag_vals) { flag_vals->swap_prio = strtoll(strchr(p, '=') + 1, NULL, 0); } else if ((fl[i].flag == MF_ZRAMSIZE) && flag_vals) { - flag_vals->zram_size = strtoll(strchr(p, '=') + 1, NULL, 0); + int is_percent = !!strrchr(p, '%'); + unsigned int val = strtoll(strchr(p, '=') + 1, NULL, 0); + if (is_percent) + flag_vals->zram_size = calculate_zram_size(val); + else + flag_vals->zram_size = val; } break; } @@ -418,6 +439,11 @@ return fstab->fs_mgr_flags & MF_NONREMOVABLE; } +int fs_mgr_is_verified(struct fstab_rec *fstab) +{ + return fstab->fs_mgr_flags & MF_VERIFY; +} + int fs_mgr_is_encryptable(struct fstab_rec *fstab) { return fstab->fs_mgr_flags & (MF_CRYPT | MF_FORCECRYPT); @@ -427,3 +453,8 @@ { return fstab->fs_mgr_flags & MF_NOEMULATEDSD; } + +int fs_mgr_is_formattable(struct fstab_rec *fstab) +{ + return fstab->fs_mgr_flags & (MF_FORMATTABLE); +}
diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 34938fa..fd58306 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h
@@ -75,6 +75,7 @@ #define MF_FORCECRYPT 0x400 #define MF_NOEMULATEDSD 0x800 /* no emulated sdcard daemon, sd card is the only external storage */ +#define MF_FORMATTABLE 0x1000 #define DM_BUF_SIZE 4096
diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_verity.h index 6193784..f90e596 100644 --- a/fs_mgr/fs_mgr_priv_verity.h +++ b/fs_mgr/fs_mgr_priv_verity.h
@@ -14,4 +14,7 @@ * limitations under the License. */ -int fs_mgr_setup_verity(struct fstab_rec *fstab); \ No newline at end of file +#define FS_MGR_SETUP_VERITY_DISABLED -2 +#define FS_MGR_SETUP_VERITY_FAIL -1 +#define FS_MGR_SETUP_VERITY_SUCCESS 0 +int fs_mgr_setup_verity(struct fstab_rec *fstab);
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c index b79a4a8..a82db4e 100644 --- a/fs_mgr/fs_mgr_verity.c +++ b/fs_mgr/fs_mgr_verity.c
@@ -43,7 +43,6 @@ #include "fs_mgr_priv_verity.h" #define VERITY_METADATA_SIZE 32768 -#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001 #define VERITY_TABLE_RSA_KEY "/verity_key" extern struct fs_info info; @@ -87,11 +86,11 @@ static int verify_table(char *signature, char *table, int table_length) { RSAPublicKey *key; - uint8_t hash_buf[SHA_DIGEST_SIZE]; + uint8_t hash_buf[SHA256_DIGEST_SIZE]; int retval = -1; // Hash the table - SHA_hash((uint8_t*)table, table_length, hash_buf); + SHA256_hash((uint8_t*)table, table_length, hash_buf); // Now get the public key from the keyfile key = load_key(VERITY_TABLE_RSA_KEY); @@ -105,7 +104,7 @@ (uint8_t*) signature, RSANUMBYTES, (uint8_t*) hash_buf, - SHA_DIGEST_SIZE)) { + SHA256_DIGEST_SIZE)) { ERROR("Couldn't verify table."); goto out; } @@ -123,28 +122,28 @@ struct ext4_super_block sb; struct fs_info info = {0}; - data_device = open(blk_device, O_RDONLY); - if (data_device < 0) { + data_device = TEMP_FAILURE_RETRY(open(blk_device, O_RDONLY | O_CLOEXEC)); + if (data_device == -1) { ERROR("Error opening block device (%s)", strerror(errno)); return -1; } - if (lseek64(data_device, 1024, SEEK_SET) < 0) { + if (TEMP_FAILURE_RETRY(lseek64(data_device, 1024, SEEK_SET)) < 0) { ERROR("Error seeking to superblock"); - close(data_device); + TEMP_FAILURE_RETRY(close(data_device)); return -1; } - if (read(data_device, &sb, sizeof(sb)) != sizeof(sb)) { + if (TEMP_FAILURE_RETRY(read(data_device, &sb, sizeof(sb))) != sizeof(sb)) { ERROR("Error reading superblock"); - close(data_device); + TEMP_FAILURE_RETRY(close(data_device)); return -1; } ext4_parse_sb(&sb, &info); *device_size = info.len; - close(data_device); + TEMP_FAILURE_RETRY(close(data_device)); return 0; } @@ -154,11 +153,13 @@ unsigned table_length; uint64_t device_length; int protocol_version; - FILE *device; - int retval = -1; + int device; + int retval = FS_MGR_SETUP_VERITY_FAIL; + *signature = 0; + *table = 0; - device = fopen(block_device, "r"); - if (!device) { + device = TEMP_FAILURE_RETRY(open(block_device, O_RDONLY | O_CLOEXEC)); + if (device == -1) { ERROR("Could not open block device %s (%s).\n", block_device, strerror(errno)); goto out; } @@ -168,23 +169,35 @@ ERROR("Could not get target device size.\n"); goto out; } - if (fseek(device, device_length, SEEK_SET) < 0) { + if (TEMP_FAILURE_RETRY(lseek64(device, device_length, SEEK_SET)) < 0) { ERROR("Could not seek to start of verity metadata block.\n"); goto out; } // check the magic number - if (!fread(&magic_number, sizeof(int), 1, device)) { + if (TEMP_FAILURE_RETRY(read(device, &magic_number, sizeof(magic_number))) != + sizeof(magic_number)) { ERROR("Couldn't read magic number!\n"); goto out; } + +#ifdef ALLOW_ADBD_DISABLE_VERITY + if (magic_number == VERITY_METADATA_MAGIC_DISABLE) { + retval = FS_MGR_SETUP_VERITY_DISABLED; + INFO("Attempt to cleanly disable verity - only works in USERDEBUG"); + goto out; + } +#endif + if (magic_number != VERITY_METADATA_MAGIC_NUMBER) { - ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", device_length); + ERROR("Couldn't find verity metadata at offset %"PRIu64"!\n", + device_length); goto out; } // check the protocol version - if (!fread(&protocol_version, sizeof(int), 1, device)) { + if (TEMP_FAILURE_RETRY(read(device, &protocol_version, + sizeof(protocol_version))) != sizeof(protocol_version)) { ERROR("Couldn't read verity metadata protocol version!\n"); goto out; } @@ -194,43 +207,49 @@ } // get the signature - *signature = (char*) malloc(RSANUMBYTES * sizeof(char)); + *signature = (char*) malloc(RSANUMBYTES); if (!*signature) { ERROR("Couldn't allocate memory for signature!\n"); goto out; } - if (!fread(*signature, RSANUMBYTES, 1, device)) { + if (TEMP_FAILURE_RETRY(read(device, *signature, RSANUMBYTES)) != RSANUMBYTES) { ERROR("Couldn't read signature from verity metadata!\n"); - free(*signature); goto out; } // get the size of the table - if (!fread(&table_length, sizeof(int), 1, device)) { + if (TEMP_FAILURE_RETRY(read(device, &table_length, sizeof(table_length))) != + sizeof(table_length)) { ERROR("Couldn't get the size of the verity table from metadata!\n"); - free(*signature); goto out; } // get the table + null terminator - table_length += 1; - *table = malloc(table_length); - if(!*table) { + *table = malloc(table_length + 1); + if (!*table) { ERROR("Couldn't allocate memory for verity table!\n"); goto out; } - if (!fgets(*table, table_length, device)) { + if (TEMP_FAILURE_RETRY(read(device, *table, table_length)) != + (ssize_t)table_length) { ERROR("Couldn't read the verity table from metadata!\n"); - free(*table); - free(*signature); goto out; } - retval = 0; + (*table)[table_length] = 0; + retval = FS_MGR_SETUP_VERITY_SUCCESS; out: - if (device) - fclose(device); + if (device != -1) + TEMP_FAILURE_RETRY(close(device)); + + if (retval != FS_MGR_SETUP_VERITY_SUCCESS) { + free(*table); + free(*signature); + *table = 0; + *signature = 0; + } + return retval; } @@ -357,11 +376,12 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { - int retval = -1; + int retval = FS_MGR_SETUP_VERITY_FAIL; + int fd = -1; - char *verity_blk_name; - char *verity_table; - char *verity_table_signature; + char *verity_blk_name = 0; + char *verity_table = 0; + char *verity_table_signature = 0; char buffer[DM_BUF_SIZE]; struct dm_ioctl *io = (struct dm_ioctl *) buffer; @@ -378,11 +398,21 @@ return retval; } + // read the verity block at the end of the block device + // send error code up the chain so we can detect attempts to disable verity + retval = read_verity_metadata(fstab->blk_device, + &verity_table_signature, + &verity_table); + if (retval < 0) { + goto out; + } + + retval = FS_MGR_SETUP_VERITY_FAIL; + // get the device mapper fd - int fd; if ((fd = open("/dev/device-mapper", O_RDWR)) < 0) { ERROR("Error opening device mapper (%s)", strerror(errno)); - return retval; + goto out; } // create the device @@ -397,13 +427,6 @@ goto out; } - // read the verity block at the end of the block device - if (read_verity_metadata(fstab->blk_device, - &verity_table_signature, - &verity_table) < 0) { - goto out; - } - // verify the signature on the table if (verify_table(verity_table_signature, verity_table, @@ -424,6 +447,7 @@ // assign the new verity block device as the block device free(fstab->blk_device); fstab->blk_device = verity_blk_name; + verity_blk_name = 0; // make sure we've set everything up properly if (test_access(fstab->blk_device) < 0) { @@ -434,6 +458,13 @@ retval = set_verified_property(mount_point); out: - close(fd); + if (fd != -1) { + close(fd); + } + + free(verity_table); + free(verity_table_signature); + free(verity_blk_name); + return retval; }
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 0c7eb20..5a6ad2d 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h
@@ -20,6 +20,13 @@ #include <stdint.h> #include <linux/dm-ioctl.h> +// Magic number at start of verity metadata +#define VERITY_METADATA_MAGIC_NUMBER 0xb001b001 + +// Replacement magic number at start of verity metadata to cleanly +// turn verity off in userdebug builds. +#define VERITY_METADATA_MAGIC_DISABLE 0x46464f56 // "VOFF" + #ifdef __cplusplus extern "C" { #endif @@ -74,9 +81,14 @@ struct fstab_rec *fs_mgr_get_entry_for_mount_point(struct fstab *fstab, const char *path); int fs_mgr_is_voldmanaged(struct fstab_rec *fstab); int fs_mgr_is_nonremovable(struct fstab_rec *fstab); +int fs_mgr_is_verified(struct fstab_rec *fstab); int fs_mgr_is_encryptable(struct fstab_rec *fstab); int fs_mgr_is_noemulatedsd(struct fstab_rec *fstab); +int fs_mgr_is_formattable(struct fstab_rec *fstab); int fs_mgr_swapon_all(struct fstab *fstab); + +int fs_mgr_do_format(struct fstab_rec *fstab); + #ifdef __cplusplus } #endif
diff --git a/include/cutils/debugger.h b/include/cutils/debugger.h index 4bcc8e6..bae687d 100644 --- a/include/cutils/debugger.h +++ b/include/cutils/debugger.h
@@ -64,11 +64,26 @@ */ int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen); +/* Dumps a process backtrace, registers, and stack to a tombstone file (requires root). + * Stores the tombstone path in the provided buffer. + * If reading debugger data from debuggerd ever takes longer than timeout_secs + * seconds, then stop and return an error. + * Returns 0 on success, -1 on error. + */ +int dump_tombstone_timeout(pid_t tid, char* pathbuf, size_t pathlen, int timeout_secs); + /* Dumps a process backtrace only to the specified file (requires root). * Returns 0 on success, -1 on error. */ int dump_backtrace_to_file(pid_t tid, int fd); +/* Dumps a process backtrace only to the specified file (requires root). + * If reading debugger data from debuggerd ever takes longer than timeout_secs + * seconds, then stop and return an error. + * Returns 0 on success, -1 on error. + */ +int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs); + #ifdef __cplusplus } #endif
diff --git a/include/nativebridge/native_bridge.h b/include/nativebridge/native_bridge.h index ac254e9..523dc49 100644 --- a/include/nativebridge/native_bridge.h +++ b/include/nativebridge/native_bridge.h
@@ -37,7 +37,7 @@ // Do the early initialization part of the native bridge, if necessary. This should be done under // high privileges. -void PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set); +bool PreInitializeNativeBridge(const char* app_data_dir, const char* instruction_set); // Initialize the native bridge, if any. Should be called by Runtime::DidForkFromZygote. The JNIEnv* // will be used to modify the app environment for the bridge.
diff --git a/include/private/android_filesystem_config.h b/include/private/android_filesystem_config.h index 5d9c3ea..2f528b9 100644 --- a/include/private/android_filesystem_config.h +++ b/include/private/android_filesystem_config.h
@@ -248,7 +248,6 @@ { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/librank" }, { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procrank" }, { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/procmem" }, - { 06755, AID_ROOT, AID_ROOT, 0, "system/xbin/tcpdump" }, { 04770, AID_ROOT, AID_RADIO, 0, "system/bin/pppd-ril" }, /* the following files have enhanced capabilities and ARE included in user builds. */
diff --git a/include/system/audio.h b/include/system/audio.h index df454ff..181a171 100644 --- a/include/system/audio.h +++ b/include/system/audio.h
@@ -57,10 +57,14 @@ * and must be routed to speaker */ AUDIO_STREAM_DTMF = 8, - AUDIO_STREAM_TTS = 9, - - AUDIO_STREAM_CNT, - AUDIO_STREAM_MAX = AUDIO_STREAM_CNT - 1, + AUDIO_STREAM_TTS = 9, /* Transmitted Through Speaker. + * Plays over speaker only, silent on other devices. + */ + AUDIO_STREAM_ACCESSIBILITY = 10, /* For accessibility talk back prompts */ + AUDIO_STREAM_REROUTING = 11, /* For dynamic policy output mixes */ + AUDIO_STREAM_PATCH = 12, /* For internal audio flinger tracks. Fixed volume */ + AUDIO_STREAM_PUBLIC_CNT = AUDIO_STREAM_TTS + 1, + AUDIO_STREAM_CNT = AUDIO_STREAM_PATCH + 1, } audio_stream_type_t; /* Do not change these values without updating their counterparts @@ -96,6 +100,7 @@ AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12, AUDIO_USAGE_ASSISTANCE_SONIFICATION = 13, AUDIO_USAGE_GAME = 14, + AUDIO_USAGE_VIRTUAL_SOURCE = 15, AUDIO_USAGE_CNT, AUDIO_USAGE_MAX = AUDIO_USAGE_CNT - 1,
diff --git a/init/Android.mk b/init/Android.mk index 489dc93..228e645 100644 --- a/init/Android.mk +++ b/init/Android.mk
@@ -45,7 +45,9 @@ libc \ libselinux \ libmincrypt \ - libext4_utils_static + libext4_utils_static \ + libsparse_static \ + libz LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
diff --git a/init/devices.c b/init/devices.c index 1012fee..73fe223 100644 --- a/init/devices.c +++ b/init/devices.c
@@ -564,7 +564,7 @@ make_device(devpath, path, block, major, minor, (const char **)links); if (links) { for (i = 0; links[i]; i++) - make_link(devpath, links[i]); + make_link_init(devpath, links[i]); } }
diff --git a/init/property_service.c b/init/property_service.c index 1902b77..91ef251 100644 --- a/init/property_service.c +++ b/init/property_service.c
@@ -540,6 +540,7 @@ { load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL); load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT, NULL); + load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL); load_properties_from_file(PROP_PATH_FACTORY, "ro.*"); load_override_properties();
diff --git a/init/util.c b/init/util.c index 0f69e1c..12cb11d 100644 --- a/init/util.c +++ b/init/util.c
@@ -329,13 +329,13 @@ if (!s) return; - for (; *s; s++) { + while (*s) { s += strspn(s, accept); - if (*s) *s = '_'; + if (*s) *s++ = '_'; } } -void make_link(const char *oldpath, const char *newpath) +void make_link_init(const char *oldpath, const char *newpath) { int ret; char buf[256];
diff --git a/init/util.h b/init/util.h index 04b8129..a7e7c8b 100644 --- a/init/util.h +++ b/init/util.h
@@ -33,7 +33,7 @@ int mkdir_recursive(const char *pathname, mode_t mode); void sanitize(char *p); -void make_link(const char *oldpath, const char *newpath); +void make_link_init(const char *oldpath, const char *newpath); void remove_link(const char *oldpath, const char *newpath); int wait_for_file(const char *filename, int timeout); void open_devnull_stdio(void);
diff --git a/libbacktrace/Android.mk b/libbacktrace/Android.mk index c321369..9588dd6 100755 --- a/libbacktrace/Android.mk +++ b/libbacktrace/Android.mk
@@ -64,6 +64,10 @@ libbacktrace_static_libraries_host := \ libcutils \ +libbacktrace_ldlibs_host := \ + -lpthread \ + -lrt \ + module := libbacktrace module_tag := optional build_type := target @@ -105,6 +109,10 @@ libbacktrace_libc++_static_libraries_host := \ libcutils \ +libbacktrace_libc++_ldlibs_host := \ + -lpthread \ + -lrt \ + libbacktrace_libc++_libc++ := true module := libbacktrace_libc++
diff --git a/libbacktrace/BacktraceThread.cpp b/libbacktrace/BacktraceThread.cpp index b47cd2a..439cc3b 100644 --- a/libbacktrace/BacktraceThread.cpp +++ b/libbacktrace/BacktraceThread.cpp
@@ -17,14 +17,15 @@ #include <errno.h> #include <inttypes.h> #include <limits.h> -#include <linux/futex.h> #include <pthread.h> #include <signal.h> +#include <stdlib.h> #include <string.h> #include <sys/syscall.h> #include <sys/time.h> #include <sys/types.h> #include <ucontext.h> +#include <unistd.h> #include <cutils/atomic.h> @@ -32,10 +33,6 @@ #include "BacktraceThread.h" #include "thread_utils.h" -static inline int futex(volatile int* uaddr, int op, int val, const struct timespec* ts, volatile int* uaddr2, int val3) { - return syscall(__NR_futex, uaddr, op, val, ts, uaddr2, val3); -} - //------------------------------------------------------------------------- // ThreadEntry implementation. //------------------------------------------------------------------------- @@ -45,7 +42,14 @@ // Assumes that ThreadEntry::list_mutex_ has already been locked before // creating a ThreadEntry object. ThreadEntry::ThreadEntry(pid_t pid, pid_t tid) - : pid_(pid), tid_(tid), futex_(0), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), next_(ThreadEntry::list_), prev_(NULL) { + : pid_(pid), tid_(tid), ref_count_(1), mutex_(PTHREAD_MUTEX_INITIALIZER), + wait_mutex_(PTHREAD_MUTEX_INITIALIZER), wait_value_(0), + next_(ThreadEntry::list_), prev_(NULL) { + pthread_condattr_t attr; + pthread_condattr_init(&attr); + pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); + pthread_cond_init(&wait_cond_, &attr); + // Add ourselves to the list. if (ThreadEntry::list_) { ThreadEntry::list_->prev_ = this; @@ -99,22 +103,35 @@ next_ = NULL; prev_ = NULL; + + pthread_cond_destroy(&wait_cond_); } void ThreadEntry::Wait(int value) { timespec ts; - ts.tv_sec = 10; - ts.tv_nsec = 0; - errno = 0; - futex(&futex_, FUTEX_WAIT, value, &ts, NULL, 0); - if (errno != 0 && errno != EWOULDBLOCK) { - BACK_LOGW("futex wait failed, futex = %d: %s", futex_, strerror(errno)); + if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) { + BACK_LOGW("clock_gettime failed: %s", strerror(errno)); + abort(); } + ts.tv_sec += 10; + + pthread_mutex_lock(&wait_mutex_); + while (wait_value_ != value) { + int ret = pthread_cond_timedwait(&wait_cond_, &wait_mutex_, &ts); + if (ret != 0) { + BACK_LOGW("pthread_cond_timedwait failed: %s", strerror(ret)); + break; + } + } + pthread_mutex_unlock(&wait_mutex_); } void ThreadEntry::Wake() { - futex_++; - futex(&futex_, FUTEX_WAKE, INT_MAX, NULL, NULL, 0); + pthread_mutex_lock(&wait_mutex_); + wait_value_++; + pthread_mutex_unlock(&wait_mutex_); + + pthread_cond_signal(&wait_cond_); } void ThreadEntry::CopyUcontextFromSigcontext(void* sigcontext) { @@ -142,7 +159,7 @@ // Pause the thread until the unwind is complete. This avoids having // the thread run ahead causing problems. - entry->Wait(1); + entry->Wait(2); ThreadEntry::Remove(entry); } @@ -194,7 +211,7 @@ } // Wait for the thread to get the ucontext. - entry->Wait(0); + entry->Wait(1); // After the thread has received the signal, allow other unwinders to // continue.
diff --git a/libbacktrace/BacktraceThread.h b/libbacktrace/BacktraceThread.h index ff3e9f3..99a8638 100644 --- a/libbacktrace/BacktraceThread.h +++ b/libbacktrace/BacktraceThread.h
@@ -48,8 +48,10 @@ inline void Lock() { pthread_mutex_lock(&mutex_); - // Reset the futex value in case of multiple unwinds of the same thread. - futex_ = 0; + + // Always reset the wait value since this could be the first or nth + // time this entry is locked. + wait_value_ = 0; } inline void Unlock() { @@ -66,9 +68,11 @@ pid_t pid_; pid_t tid_; - int futex_; int ref_count_; pthread_mutex_t mutex_; + pthread_mutex_t wait_mutex_; + pthread_cond_t wait_cond_; + int wait_value_; ThreadEntry* next_; ThreadEntry* prev_; ucontext_t ucontext_;
diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index ed6b211..8002ed6 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp
@@ -51,7 +51,7 @@ #define NS_PER_SEC 1000000000ULL // Number of simultaneous dumping operations to perform. -#define NUM_THREADS 20 +#define NUM_THREADS 40 // Number of simultaneous threads running in our forked process. #define NUM_PTRACE_THREADS 5 @@ -486,6 +486,13 @@ struct sigaction new_action; ASSERT_TRUE(sigaction(THREAD_SIGNAL, NULL, &new_action) == 0); EXPECT_EQ(cur_action.sa_sigaction, new_action.sa_sigaction); + // The SA_RESTORER flag gets set behind our back, so a direct comparison + // doesn't work unless we mask the value off. Mips doesn't have this + // flag, so skip this on that platform. +#ifdef SA_RESTORER + cur_action.sa_flags &= ~SA_RESTORER; + new_action.sa_flags &= ~SA_RESTORER; +#endif EXPECT_EQ(cur_action.sa_flags, new_action.sa_flags); } @@ -583,7 +590,7 @@ // Wait for tids to be set. for (std::vector<thread_t>::iterator it = runners.begin(); it != runners.end(); ++it) { - ASSERT_TRUE(WaitForNonZero(&it->state, 10)); + ASSERT_TRUE(WaitForNonZero(&it->state, 30)); } // Start all of the dumpers at once, they will spin until they are signalled @@ -602,7 +609,7 @@ android_atomic_acquire_store(1, &dump_now); for (size_t i = 0; i < NUM_THREADS; i++) { - ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 10)); + ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30)); // Tell the runner thread to exit its infinite loop. android_atomic_acquire_store(0, &runners[i].state); @@ -625,7 +632,7 @@ ASSERT_TRUE(pthread_create(&runner.threadId, &attr, ThreadMaxRun, &runner) == 0); // Wait for tids to be set. - ASSERT_TRUE(WaitForNonZero(&runner.state, 10)); + ASSERT_TRUE(WaitForNonZero(&runner.state, 30)); // Start all of the dumpers at once, they will spin until they are signalled // to begin their dump run. @@ -645,7 +652,7 @@ android_atomic_acquire_store(1, &dump_now); for (size_t i = 0; i < NUM_THREADS; i++) { - ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 100)); + ASSERT_TRUE(WaitForNonZero(&dumpers[i].done, 30)); ASSERT_TRUE(dumpers[i].backtrace != NULL); VerifyMaxDump(dumpers[i].backtrace);
diff --git a/libcutils/debugger.c b/libcutils/debugger.c index 4035ee1..b8a2efc 100644 --- a/libcutils/debugger.c +++ b/libcutils/debugger.c
@@ -19,11 +19,16 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/types.h> +#include <sys/socket.h> #include <unistd.h> #include <cutils/debugger.h> #include <cutils/sockets.h> +#define LOG_TAG "DEBUG" +#include <log/log.h> + #if defined(__LP64__) #include <elf.h> @@ -64,7 +69,7 @@ return result; } -static int make_dump_request(debugger_action_t action, pid_t tid) { +static int make_dump_request(debugger_action_t action, pid_t tid, int timeout_secs) { const char* socket_name; debugger_msg_t msg; size_t msg_len; @@ -98,6 +103,19 @@ return -1; } + if (timeout_secs > 0) { + struct timeval tm; + tm.tv_sec = timeout_secs; + tm.tv_usec = 0; + if (setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &tm, sizeof(tm)) == -1) { + ALOGE("WARNING: Cannot set receive timeout value on socket: %s", strerror(errno)); + } + + if (setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, &tm, sizeof(tm)) == -1) { + ALOGE("WARNING: Cannot set send timeout value on socket: %s", strerror(errno)); + } + } + if (send_request(sock_fd, msg_ptr, msg_len) < 0) { TEMP_FAILURE_RETRY(close(sock_fd)); return -1; @@ -107,7 +125,11 @@ } int dump_backtrace_to_file(pid_t tid, int fd) { - int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid); + return dump_backtrace_to_file_timeout(tid, fd, 0); +} + +int dump_backtrace_to_file_timeout(pid_t tid, int fd, int timeout_secs) { + int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_BACKTRACE, tid, timeout_secs); if (sock_fd < 0) { return -1; } @@ -127,7 +149,11 @@ } int dump_tombstone(pid_t tid, char* pathbuf, size_t pathlen) { - int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid); + return dump_tombstone_timeout(tid, pathbuf, pathlen, 0); +} + +int dump_tombstone_timeout(pid_t tid, char* pathbuf, size_t pathlen, int timeout_secs) { + int sock_fd = make_dump_request(DEBUGGER_ACTION_DUMP_TOMBSTONE, tid, timeout_secs); if (sock_fd < 0) { return -1; }
diff --git a/libcutils/sched_policy.c b/libcutils/sched_policy.c index 2acc3c3..493511e 100644 --- a/libcutils/sched_policy.c +++ b/libcutils/sched_policy.c
@@ -45,8 +45,6 @@ #define POLICY_DEBUG 0 -#define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM) - // This prctl is only available in Android kernels. #define PR_SET_TIMERSLACK_PID 41 @@ -60,9 +58,6 @@ // File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error. static int bg_cgroup_fd = -1; static int fg_cgroup_fd = -1; -#if CAN_SET_SP_SYSTEM -static int system_cgroup_fd = -1; -#endif /* Add tid to the scheduling group defined by the policy */ static int add_tid_to_cgroup(int tid, SchedPolicy policy) @@ -78,11 +73,6 @@ case SP_AUDIO_SYS: fd = fg_cgroup_fd; break; -#if CAN_SET_SP_SYSTEM - case SP_SYSTEM: - fd = system_cgroup_fd; - break; -#endif default: fd = -1; break; @@ -123,21 +113,13 @@ if (!access("/dev/cpuctl/tasks", F_OK)) { __sys_supports_schedgroups = 1; -#if CAN_SET_SP_SYSTEM filename = "/dev/cpuctl/tasks"; - system_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC); - if (system_cgroup_fd < 0) { - SLOGV("open of %s failed: %s\n", filename, strerror(errno)); - } -#endif - - filename = "/dev/cpuctl/apps/tasks"; fg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC); if (fg_cgroup_fd < 0) { SLOGE("open of %s failed: %s\n", filename, strerror(errno)); } - filename = "/dev/cpuctl/apps/bg_non_interactive/tasks"; + filename = "/dev/cpuctl/bg_non_interactive/tasks"; bg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC); if (bg_cgroup_fd < 0) { SLOGE("open of %s failed: %s\n", filename, strerror(errno)); @@ -233,11 +215,9 @@ if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0) return -1; if (grpBuf[0] == '\0') { - *policy = SP_SYSTEM; - } else if (!strcmp(grpBuf, "apps/bg_non_interactive")) { - *policy = SP_BACKGROUND; - } else if (!strcmp(grpBuf, "apps")) { *policy = SP_FOREGROUND; + } else if (!strcmp(grpBuf, "bg_non_interactive")) { + *policy = SP_BACKGROUND; } else { errno = ERANGE; return -1;
diff --git a/liblog/tests/Android.mk b/liblog/tests/Android.mk index 255dc2e..cd1bf33 100644 --- a/liblog/tests/Android.mk +++ b/liblog/tests/Android.mk
@@ -59,7 +59,8 @@ -g \ -Wall -Wextra \ -Werror \ - -fno-builtin + -fno-builtin \ + -std=gnu++11 test_src_files := \ liblog_test.cpp
diff --git a/libnativebridge/Android.mk b/libnativebridge/Android.mk index 6c2e43e..83169eb 100644 --- a/libnativebridge/Android.mk +++ b/libnativebridge/Android.mk
@@ -13,7 +13,7 @@ LOCAL_SHARED_LIBRARIES := liblog LOCAL_CLANG := true LOCAL_CPP_EXTENSION := .cc -LOCAL_CFLAGS := -Werror -Wall +LOCAL_CFLAGS += -Werror -Wall LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected LOCAL_LDFLAGS := -ldl LOCAL_MULTILIB := both @@ -30,11 +30,11 @@ LOCAL_SHARED_LIBRARIES := liblog LOCAL_CLANG := true LOCAL_CPP_EXTENSION := .cc -LOCAL_CFLAGS := -Werror -Wall +LOCAL_CFLAGS += -Werror -Wall LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected LOCAL_LDFLAGS := -ldl LOCAL_MULTILIB := both include $(BUILD_HOST_SHARED_LIBRARY) -include $(LOCAL_PATH)/tests/Android.mk \ No newline at end of file +include $(LOCAL_PATH)/tests/Android.mk
diff --git a/libnativebridge/native_bridge.cc b/libnativebridge/native_bridge.cc index 3facedd..eab2de0 100644 --- a/libnativebridge/native_bridge.cc +++ b/libnativebridge/native_bridge.cc
@@ -43,14 +43,16 @@ enum class NativeBridgeState { kNotSetup, // Initial state. kOpened, // After successful dlopen. + kPreInitialized, // After successful pre-initialization. kInitialized, // After successful initialization. kClosed // Closed or errors. }; -static const char* kNotSetupString = "kNotSetup"; -static const char* kOpenedString = "kOpened"; -static const char* kInitializedString = "kInitialized"; -static const char* kClosedString = "kClosed"; +static constexpr const char* kNotSetupString = "kNotSetup"; +static constexpr const char* kOpenedString = "kOpened"; +static constexpr const char* kPreInitializedString = "kPreInitialized"; +static constexpr const char* kInitializedString = "kInitialized"; +static constexpr const char* kClosedString = "kClosed"; static const char* GetNativeBridgeStateString(NativeBridgeState state) { switch (state) { @@ -60,6 +62,9 @@ case NativeBridgeState::kOpened: return kOpenedString; + case NativeBridgeState::kPreInitialized: + return kPreInitializedString; + case NativeBridgeState::kInitialized: return kInitializedString; @@ -82,8 +87,14 @@ // Callbacks provided by the environment to the bridge. Passed to LoadNativeBridge. static const NativeBridgeRuntimeCallbacks* runtime_callbacks = nullptr; -// The app's data directory. -static char* app_data_dir = nullptr; +// The app's code cache directory. +static char* app_code_cache_dir = nullptr; + +// Code cache directory (relative to the application private directory) +// Ideally we'd like to call into framework to retrieve this name. However that's considered an +// implementation detail and will require either hacks or consistent refactorings. We compromise +// and hard code the directory name again here. +static constexpr const char* kCodeCacheDir = "code_cache"; static constexpr uint32_t kNativeBridgeCallbackVersion = 1; @@ -132,6 +143,13 @@ return cb != nullptr && cb->version == kNativeBridgeCallbackVersion; } +static void CloseNativeBridge(bool with_error) { + state = NativeBridgeState::kClosed; + had_error |= with_error; + delete[] app_code_cache_dir; + app_code_cache_dir = nullptr; +} + bool LoadNativeBridge(const char* nb_library_filename, const NativeBridgeRuntimeCallbacks* runtime_cbs) { // We expect only one place that calls LoadNativeBridge: Runtime::Init. At that point we are not @@ -149,12 +167,11 @@ } if (nb_library_filename == nullptr || *nb_library_filename == 0) { - state = NativeBridgeState::kClosed; - return true; + CloseNativeBridge(false); + return false; } else { if (!NativeBridgeNameAcceptable(nb_library_filename)) { - state = NativeBridgeState::kClosed; - had_error = true; + CloseNativeBridge(true); } else { // Try to open the library. void* handle = dlopen(nb_library_filename, RTLD_LAZY); @@ -178,8 +195,7 @@ // Two failure conditions: could not find library (dlopen failed), or could not find native // bridge interface (dlsym failed). Both are an error and close the native bridge. if (callbacks == nullptr) { - had_error = true; - state = NativeBridgeState::kClosed; + CloseNativeBridge(true); } else { runtime_callbacks = runtime_cbs; state = NativeBridgeState::kOpened; @@ -216,19 +232,32 @@ template<typename T> void UNUSED(const T&) {} #endif -void PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) { - if (app_data_dir_in == nullptr) { - return; +bool PreInitializeNativeBridge(const char* app_data_dir_in, const char* instruction_set) { + if (state != NativeBridgeState::kOpened) { + ALOGE("Invalid state: native bridge is expected to be opened."); + CloseNativeBridge(true); + return false; } - const size_t len = strlen(app_data_dir_in); - // Make a copy for us. - app_data_dir = new char[len]; - strncpy(app_data_dir, app_data_dir_in, len); + if (app_data_dir_in == nullptr) { + ALOGE("Application private directory cannot be null."); + CloseNativeBridge(true); + return false; + } + + // Create the path to the application code cache directory. + // The memory will be release after Initialization or when the native bridge is closed. + const size_t len = strlen(app_data_dir_in) + strlen(kCodeCacheDir) + 2; // '\0' + '/' + app_code_cache_dir = new char[len]; + snprintf(app_code_cache_dir, len, "%s/%s", app_data_dir_in, kCodeCacheDir); + + // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo. + // Failure is not fatal and will keep the native bridge in kPreInitialized. + state = NativeBridgeState::kPreInitialized; #ifndef __APPLE__ if (instruction_set == nullptr) { - return; + return true; } size_t isa_len = strlen(instruction_set); if (isa_len > 10) { @@ -237,11 +266,11 @@ // be another instruction set in the future. ALOGW("Instruction set %s is malformed, must be less than or equal to 10 characters.", instruction_set); - return; + return true; } - // Bind-mount /system/lib{,64}/<isa>/cpuinfo to /proc/cpuinfo. If the file does not exist, the - // mount command will fail, so we safe the extra file existence check... + // If the file does not exist, the mount command will fail, + // so we save the extra file existence check. char cpuinfo_path[1024]; #ifdef HAVE_ANDROID_OS @@ -263,10 +292,12 @@ nullptr)) == -1) { // "Data." ALOGW("Failed to bind-mount %s as /proc/cpuinfo: %s", cpuinfo_path, strerror(errno)); } -#else +#else // __APPLE__ UNUSED(instruction_set); ALOGW("Mac OS does not support bind-mounting. Host simulation of native bridge impossible."); #endif + + return true; } static void SetCpuAbi(JNIEnv* env, jclass build_class, const char* field, const char* value) { @@ -353,20 +384,40 @@ // We expect only one place that calls InitializeNativeBridge: Runtime::DidForkFromZygote. At that // point we are not multi-threaded, so we do not need locking here. - if (state == NativeBridgeState::kOpened) { - // Try to initialize. - if (callbacks->initialize(runtime_callbacks, app_data_dir, instruction_set)) { - SetupEnvironment(callbacks, env, instruction_set); - state = NativeBridgeState::kInitialized; - } else { - // Unload the library. - dlclose(native_bridge_handle); - had_error = true; - state = NativeBridgeState::kClosed; + if (state == NativeBridgeState::kPreInitialized) { + // Check for code cache: if it doesn't exist try to create it. + struct stat st; + if (stat(app_code_cache_dir, &st) == -1) { + if (errno == ENOENT) { + if (mkdir(app_code_cache_dir, S_IRWXU | S_IRWXG | S_IXOTH) == -1) { + ALOGE("Cannot create code cache directory %s: %s.", app_code_cache_dir, strerror(errno)); + CloseNativeBridge(true); + } + } else { + ALOGE("Cannot stat code cache directory %s: %s.", app_code_cache_dir, strerror(errno)); + CloseNativeBridge(true); + } + } else if (!S_ISDIR(st.st_mode)) { + ALOGE("Code cache is not a directory %s.", app_code_cache_dir); + CloseNativeBridge(true); + } + + // If we're still PreInitialized (dind't fail the code cache checks) try to initialize. + if (state == NativeBridgeState::kPreInitialized) { + if (callbacks->initialize(runtime_callbacks, app_code_cache_dir, instruction_set)) { + SetupEnvironment(callbacks, env, instruction_set); + state = NativeBridgeState::kInitialized; + // We no longer need the code cache path, release the memory. + delete[] app_code_cache_dir; + app_code_cache_dir = nullptr; + } else { + // Unload the library. + dlclose(native_bridge_handle); + CloseNativeBridge(true); + } } } else { - had_error = true; - state = NativeBridgeState::kClosed; + CloseNativeBridge(true); } return state == NativeBridgeState::kInitialized; @@ -378,22 +429,22 @@ switch(state) { case NativeBridgeState::kOpened: + case NativeBridgeState::kPreInitialized: case NativeBridgeState::kInitialized: // Unload. dlclose(native_bridge_handle); + CloseNativeBridge(false); break; case NativeBridgeState::kNotSetup: // Not even set up. Error. - had_error = true; + CloseNativeBridge(true); break; case NativeBridgeState::kClosed: // Ignore. break; } - - state = NativeBridgeState::kClosed; } bool NativeBridgeError() { @@ -401,7 +452,9 @@ } bool NativeBridgeAvailable() { - return state == NativeBridgeState::kOpened || state == NativeBridgeState::kInitialized; + return state == NativeBridgeState::kOpened + || state == NativeBridgeState::kPreInitialized + || state == NativeBridgeState::kInitialized; } bool NativeBridgeInitialized() {
diff --git a/libnativebridge/tests/Android.mk b/libnativebridge/tests/Android.mk index 9c7e1b8..f28c490 100644 --- a/libnativebridge/tests/Android.mk +++ b/libnativebridge/tests/Android.mk
@@ -1,19 +1,29 @@ # Build the unit tests. LOCAL_PATH := $(call my-dir) + +include $(LOCAL_PATH)/Android.nativebridge-dummy.mk + include $(CLEAR_VARS) # Build the unit tests. test_src_files := \ + CodeCacheCreate_test.cpp \ + CodeCacheExists_test.cpp \ + CompleteFlow_test.cpp \ InvalidCharsNativeBridge_test.cpp \ NeedsNativeBridge_test.cpp \ PreInitializeNativeBridge_test.cpp \ + PreInitializeNativeBridgeFail1_test.cpp \ + PreInitializeNativeBridgeFail2_test.cpp \ ReSetupNativeBridge_test.cpp \ UnavailableNativeBridge_test.cpp \ ValidNameNativeBridge_test.cpp + shared_libraries := \ liblog \ - libnativebridge + libnativebridge \ + libnativebridge-dummy $(foreach file,$(test_src_files), \ $(eval include $(CLEAR_VARS)) \ @@ -33,4 +43,4 @@ $(eval LOCAL_SRC_FILES := $(file)) \ $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \ $(eval include $(BUILD_HOST_NATIVE_TEST)) \ -) \ No newline at end of file +)
diff --git a/libnativebridge/tests/Android.nativebridge-dummy.mk b/libnativebridge/tests/Android.nativebridge-dummy.mk new file mode 100644 index 0000000..1caf50a --- /dev/null +++ b/libnativebridge/tests/Android.nativebridge-dummy.mk
@@ -0,0 +1,34 @@ +LOCAL_PATH:= $(call my-dir) + +NATIVE_BRIDGE_COMMON_SRC_FILES := \ + DummyNativeBridge.cpp + +# Shared library for target +# ======================================================== +include $(CLEAR_VARS) + +LOCAL_MODULE:= libnativebridge-dummy + +LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES) +LOCAL_CLANG := true +LOCAL_CFLAGS += -Werror -Wall +LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected +LOCAL_LDFLAGS := -ldl +LOCAL_MULTILIB := both + +include $(BUILD_SHARED_LIBRARY) + +# Shared library for host +# ======================================================== +include $(CLEAR_VARS) + +LOCAL_MODULE:= libnativebridge-dummy + +LOCAL_SRC_FILES:= $(NATIVE_BRIDGE_COMMON_SRC_FILES) +LOCAL_CLANG := true +LOCAL_CFLAGS += -Werror -Wall +LOCAL_CPPFLAGS := -std=gnu++11 -fvisibility=protected +LOCAL_LDFLAGS := -ldl +LOCAL_MULTILIB := both + +include $(BUILD_HOST_SHARED_LIBRARY)
diff --git a/libnativebridge/tests/CodeCacheCreate_test.cpp b/libnativebridge/tests/CodeCacheCreate_test.cpp new file mode 100644 index 0000000..58270c4 --- /dev/null +++ b/libnativebridge/tests/CodeCacheCreate_test.cpp
@@ -0,0 +1,51 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NativeBridgeTest.h" + +#include <errno.h> +#include <sys/stat.h> +#include <unistd.h> + +namespace android { + +// Tests that the bridge initialization creates the code_cache if it doesn't +// exists. +TEST_F(NativeBridgeTest, CodeCacheCreate) { + // Make sure that code_cache does not exists + struct stat st; + ASSERT_EQ(-1, stat(kCodeCache, &st)); + ASSERT_EQ(ENOENT, errno); + + // Init + ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr)); + ASSERT_TRUE(PreInitializeNativeBridge(".", "isa")); + ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr)); + ASSERT_TRUE(NativeBridgeAvailable()); + ASSERT_FALSE(NativeBridgeError()); + + // Check that code_cache was created + ASSERT_EQ(0, stat(kCodeCache, &st)); + ASSERT_TRUE(S_ISDIR(st.st_mode)); + + // Clean up + UnloadNativeBridge(); + ASSERT_EQ(0, rmdir(kCodeCache)); + + ASSERT_FALSE(NativeBridgeError()); +} + +} // namespace android
diff --git a/libnativebridge/tests/CodeCacheExists_test.cpp b/libnativebridge/tests/CodeCacheExists_test.cpp new file mode 100644 index 0000000..8ba0158 --- /dev/null +++ b/libnativebridge/tests/CodeCacheExists_test.cpp
@@ -0,0 +1,54 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NativeBridgeTest.h" + +#include <errno.h> +#include <sys/stat.h> +#include <unistd.h> + +namespace android { + +// Tests that the bridge is initialized without errors if the code_cache already +// exists. +TEST_F(NativeBridgeTest, CodeCacheExists) { + // Make sure that code_cache does not exists + struct stat st; + ASSERT_EQ(-1, stat(kCodeCache, &st)); + ASSERT_EQ(ENOENT, errno); + + // Create the code_cache + ASSERT_EQ(0, mkdir(kCodeCache, S_IRWXU | S_IRWXG | S_IXOTH)); + + // Init + ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr)); + ASSERT_TRUE(PreInitializeNativeBridge(".", "isa")); + ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr)); + ASSERT_TRUE(NativeBridgeAvailable()); + ASSERT_FALSE(NativeBridgeError()); + + // Check that the code cache is still there + ASSERT_EQ(0, stat(kCodeCache, &st)); + ASSERT_TRUE(S_ISDIR(st.st_mode)); + + // Clean up + UnloadNativeBridge(); + ASSERT_EQ(0, rmdir(kCodeCache)); + + ASSERT_FALSE(NativeBridgeError()); +} + +} // namespace android
diff --git a/libnativebridge/tests/CompleteFlow_test.cpp b/libnativebridge/tests/CompleteFlow_test.cpp new file mode 100644 index 0000000..cf06d2c --- /dev/null +++ b/libnativebridge/tests/CompleteFlow_test.cpp
@@ -0,0 +1,46 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NativeBridgeTest.h" + +#include <unistd.h> + +namespace android { + +TEST_F(NativeBridgeTest, CompleteFlow) { + // Init + ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr)); + ASSERT_TRUE(NativeBridgeAvailable()); + ASSERT_TRUE(PreInitializeNativeBridge(".", "isa")); + ASSERT_TRUE(NativeBridgeAvailable()); + ASSERT_TRUE(InitializeNativeBridge(nullptr, nullptr)); + ASSERT_TRUE(NativeBridgeAvailable()); + + // Basic calls to check that nothing crashes + ASSERT_FALSE(NativeBridgeIsSupported(nullptr)); + ASSERT_EQ(nullptr, NativeBridgeLoadLibrary(nullptr, 0)); + ASSERT_EQ(nullptr, NativeBridgeGetTrampoline(nullptr, nullptr, nullptr, 0)); + + // Unload + UnloadNativeBridge(); + ASSERT_FALSE(NativeBridgeAvailable()); + ASSERT_FALSE(NativeBridgeError()); + + // Clean-up code_cache + ASSERT_EQ(0, rmdir(kCodeCache)); +} + +} // namespace android
diff --git a/libnativebridge/tests/DummyNativeBridge.cpp b/libnativebridge/tests/DummyNativeBridge.cpp new file mode 100644 index 0000000..b9894f6 --- /dev/null +++ b/libnativebridge/tests/DummyNativeBridge.cpp
@@ -0,0 +1,53 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// A dummy implementation of the native-bridge interface. + +#include "nativebridge/native_bridge.h" + +// NativeBridgeCallbacks implementations +extern "C" bool native_bridge_initialize(const android::NativeBridgeRuntimeCallbacks* /* art_cbs */, + const char* /* app_code_cache_dir */, + const char* /* isa */) { + return true; +} + +extern "C" void* native_bridge_loadLibrary(const char* /* libpath */, int /* flag */) { + return nullptr; +} + +extern "C" void* native_bridge_getTrampoline(void* /* handle */, const char* /* name */, + const char* /* shorty */, uint32_t /* len */) { + return nullptr; +} + +extern "C" bool native_bridge_isSupported(const char* /* libpath */) { + return false; +} + +extern "C" const struct android::NativeBridgeRuntimeValues* native_bridge_getAppEnv( + const char* /* abi */) { + return nullptr; +} + +android::NativeBridgeCallbacks NativeBridgeItf { + .version = 1, + .initialize = &native_bridge_initialize, + .loadLibrary = &native_bridge_loadLibrary, + .getTrampoline = &native_bridge_getTrampoline, + .isSupported = &native_bridge_isSupported, + .getAppEnv = &native_bridge_getAppEnv +};
diff --git a/libnativebridge/tests/NativeBridgeTest.h b/libnativebridge/tests/NativeBridgeTest.h index 0d731cb..6a5c126 100644 --- a/libnativebridge/tests/NativeBridgeTest.h +++ b/libnativebridge/tests/NativeBridgeTest.h
@@ -22,6 +22,9 @@ #include <nativebridge/native_bridge.h> #include <gtest/gtest.h> +constexpr const char* kNativeBridgeLibrary = "libnativebridge-dummy.so"; +constexpr const char* kCodeCache = "./code_cache"; + namespace android { class NativeBridgeTest : public testing::Test {
diff --git a/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp b/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp new file mode 100644 index 0000000..69c30a1 --- /dev/null +++ b/libnativebridge/tests/PreInitializeNativeBridgeFail1_test.cpp
@@ -0,0 +1,38 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NativeBridgeTest.h" + +#include <cstdio> +#include <cstring> +#include <cutils/log.h> +#include <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <sys/mount.h> +#include <sys/stat.h> + +namespace android { + +TEST_F(NativeBridgeTest, PreInitializeNativeBridgeFail1) { + // Needs a valid application directory. + ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr)); + ASSERT_FALSE(PreInitializeNativeBridge(nullptr, "isa")); + ASSERT_TRUE(NativeBridgeError()); +} + +} // namespace android
diff --git a/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp b/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp new file mode 100644 index 0000000..74e96e0 --- /dev/null +++ b/libnativebridge/tests/PreInitializeNativeBridgeFail2_test.cpp
@@ -0,0 +1,37 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "NativeBridgeTest.h" + +#include <cstdio> +#include <cstring> +#include <cutils/log.h> +#include <dlfcn.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <sys/mount.h> +#include <sys/stat.h> + +namespace android { + +TEST_F(NativeBridgeTest, PreInitializeNativeBridgeFail2) { + // Needs LoadNativeBridge() first + ASSERT_FALSE(PreInitializeNativeBridge(nullptr, "isa")); + ASSERT_TRUE(NativeBridgeError()); +} + +} // namespace android
diff --git a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp index 84078f7..cec26ce 100644 --- a/libnativebridge/tests/PreInitializeNativeBridge_test.cpp +++ b/libnativebridge/tests/PreInitializeNativeBridge_test.cpp
@@ -31,6 +31,7 @@ static constexpr const char* kTestData = "PreInitializeNativeBridge test."; TEST_F(NativeBridgeTest, PreInitializeNativeBridge) { + ASSERT_TRUE(LoadNativeBridge(kNativeBridgeLibrary, nullptr)); #ifndef __APPLE__ // Mac OS does not support bind-mount. #ifndef HAVE_ANDROID_OS // Cannot write into the hard-wired location. // Try to create our mount namespace. @@ -41,8 +42,7 @@ fprintf(cpuinfo, kTestData); fclose(cpuinfo); - // Call the setup. - PreInitializeNativeBridge("does not matter 1", "short 2"); + ASSERT_TRUE(PreInitializeNativeBridge("does not matter 1", "short 2")); // Read /proc/cpuinfo FILE* proc_cpuinfo = fopen("/proc/cpuinfo", "r");
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp index f8d6162..ee2f32d 100644 --- a/logd/LogAudit.cpp +++ b/logd/LogAudit.cpp
@@ -22,15 +22,26 @@ #include <sys/klog.h> #include <sys/prctl.h> #include <sys/uio.h> +#include <syslog.h> #include "libaudit.h" #include "LogAudit.h" +#define KMSG_PRIORITY(PRI) \ + '<', \ + '0' + (LOG_AUTH | (PRI)) / 10, \ + '0' + (LOG_AUTH | (PRI)) % 10, \ + '>' + LogAudit::LogAudit(LogBuffer *buf, LogReader *reader, int fdDmsg) : SocketListener(getLogSocket(), false) , logbuf(buf) , reader(reader) , fdDmesg(-1) { + static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO), + 'l', 'o', 'g', 'd', '.', 'a', 'u', 'd', 'i', 't', 'd', ':', + ' ', 's', 't', 'a', 'r', 't', '\n' }; + write(fdDmsg, auditd_message, sizeof(auditd_message)); logDmesg(); fdDmesg = fdDmsg; } @@ -75,13 +86,19 @@ memmove(cp, cp + 1, strlen(cp + 1) + 1); } + bool info = strstr(str, " permissive=1") || strstr(str, " policy loaded "); if (fdDmesg >= 0) { - struct iovec iov[2]; + struct iovec iov[3]; + static const char log_info[] = { KMSG_PRIORITY(LOG_INFO) }; + static const char log_warning[] = { KMSG_PRIORITY(LOG_WARNING) }; - iov[0].iov_base = str; - iov[0].iov_len = strlen(str); - iov[1].iov_base = const_cast<char *>("\n"); - iov[1].iov_len = 1; + iov[0].iov_base = info ? const_cast<char *>(log_info) + : const_cast<char *>(log_warning); + iov[0].iov_len = info ? sizeof(log_info) : sizeof(log_warning); + iov[1].iov_base = str; + iov[1].iov_len = strlen(str); + iov[2].iov_base = const_cast<char *>("\n"); + iov[2].iov_len = 1; writev(fdDmesg, iov, sizeof(iov) / sizeof(iov[0])); } @@ -175,10 +192,7 @@ if (!newstr) { rc = -ENOMEM; } else { - *newstr = (strstr(str, " permissive=1") - || strstr(str, " policy loaded ")) - ? ANDROID_LOG_INFO - : ANDROID_LOG_WARN; + *newstr = info ? ANDROID_LOG_INFO : ANDROID_LOG_WARN; strlcpy(newstr + 1, comm, l); strncpy(newstr + 1 + l, str, estr - str); strcpy(newstr + 1 + l + (estr - str), ecomm); @@ -234,7 +248,7 @@ if (fd < 0) { return fd; } - if (audit_set_pid(fd, getpid(), WAIT_YES) < 0) { + if (audit_setup(fd, getpid()) < 0) { audit_close(fd); fd = -1; }
diff --git a/logd/LogBuffer.cpp b/logd/LogBuffer.cpp index cd9ea20..8c1c344 100644 --- a/logd/LogBuffer.cpp +++ b/logd/LogBuffer.cpp
@@ -93,9 +93,9 @@ } LogBuffer::LogBuffer(LastLogTimes *times) - : mTimes(*times) { + : dgramQlenStatistics(false) + , mTimes(*times) { pthread_mutex_init(&mLogElementsLock, NULL); - dgram_qlen_statistics = false; static const char global_tuneable[] = "persist.logd.size"; // Settings App static const char global_default[] = "ro.logd.size"; // BoardConfig.mk @@ -150,10 +150,10 @@ while (--it != mLogElements.begin()) { if ((*it)->getRealTime() <= realtime) { // halves the peak performance, use with caution - if (dgram_qlen_statistics) { + if (dgramQlenStatistics) { LogBufferElementCollection::iterator ib = it; unsigned short buckets, num = 1; - for (unsigned short i = 0; (buckets = stats.dgram_qlen(i)); ++i) { + for (unsigned short i = 0; (buckets = stats.dgramQlen(i)); ++i) { buckets -= num; num += buckets; while (buckets && (--ib != mLogElements.begin())) { @@ -267,8 +267,7 @@ if (uid == caller_uid) { it = mLogElements.erase(it); - unsigned short len = e->getMsgLen(); - stats.subtract(len, id, uid, e->getPid()); + stats.subtract(e->getMsgLen(), id, uid, e->getPid()); delete e; pruneRows--; if (pruneRows == 0) { @@ -318,23 +317,19 @@ uid_t uid = e->getUid(); - if (uid == worst) { + if ((uid == worst) || mPrune.naughty(e)) { // Worst or BlackListed it = mLogElements.erase(it); unsigned short len = e->getMsgLen(); - stats.subtract(len, id, worst, e->getPid()); - delete e; - kick = true; - pruneRows--; - if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) { - break; - } - worst_sizes -= len; - } else if (mPrune.naughty(e)) { // BlackListed - it = mLogElements.erase(it); - stats.subtract(e->getMsgLen(), id, uid, e->getPid()); + stats.subtract(len, id, uid, e->getPid()); delete e; pruneRows--; - if (pruneRows == 0) { + if (uid == worst) { + kick = true; + if ((pruneRows == 0) || (worst_sizes < second_worst_sizes)) { + break; + } + worst_sizes -= len; + } else if (pruneRows == 0) { break; } } else {
diff --git a/logd/LogBuffer.h b/logd/LogBuffer.h index 4b982a8..879baea 100644 --- a/logd/LogBuffer.h +++ b/logd/LogBuffer.h
@@ -37,8 +37,7 @@ pthread_mutex_t mLogElementsLock; LogStatistics stats; - - bool dgram_qlen_statistics; + bool dgramQlenStatistics; PruneList mPrune; @@ -66,7 +65,11 @@ void enableDgramQlenStatistics() { stats.enableDgramQlenStatistics(); - dgram_qlen_statistics = true; + dgramQlenStatistics = true; + } + + void enableStatistics() { + stats.enableStatistics(); } int initPrune(char *cp) { return mPrune.init(cp); }
diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp index a2f27c6..2a45590 100644 --- a/logd/LogStatistics.cpp +++ b/logd/LogStatistics.cpp
@@ -51,11 +51,11 @@ } bool PidStatistics::pidGone() { - if (mGone) { + if (mGone || (pid == gone)) { return true; } - if (pid == gone) { - return true; + if (pid == 0) { + return false; } if (kill(pid, 0) && (errno != EPERM)) { mGone = true; @@ -90,9 +90,14 @@ } // must call free to release return value +// If only we could sniff our own logs for: +// <time> <pid> <pid> E AndroidRuntime: Process: <name>, PID: <pid> +// which debuggerd prints as a process is crashing. char *PidStatistics::pidToName(pid_t pid) { char *retval = NULL; - if (pid != gone) { + if (pid == 0) { // special case from auditd for kernel + retval = strdup("logd.auditd"); + } else if (pid != gone) { char buffer[512]; snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid); int fd = open(buffer, O_RDONLY); @@ -122,7 +127,7 @@ PidStatisticsCollection::iterator it; for (it = begin(); it != end();) { delete (*it); - it = Pids.erase(it); + it = erase(it); } } @@ -130,7 +135,7 @@ mSizes += size; ++mElements; - PidStatistics *p; + PidStatistics *p = NULL; PidStatisticsCollection::iterator last; PidStatisticsCollection::iterator it; for (last = it = begin(); it != end(); last = it, ++it) { @@ -141,12 +146,12 @@ } } // insert if the gone entry. - bool insert = (last != it) && (p->getPid() == p->gone); + bool insert_before_last = (last != it) && p && (p->getPid() == p->gone); p = new PidStatistics(pid, pidToName(pid)); - if (insert) { - Pids.insert(last, p); + if (insert_before_last) { + insert(last, p); } else { - Pids.push_back(p); + push_back(p); } p->add(size); } @@ -163,17 +168,17 @@ size_t szsTotal = p->sizesTotal(); size_t elsTotal = p->elementsTotal(); delete p; - Pids.erase(it); + erase(it); it = end(); --it; if (it == end()) { p = new PidStatistics(p->gone); - Pids.push_back(p); + push_back(p); } else { p = *it; if (p->getPid() != p->gone) { p = new PidStatistics(p->gone); - Pids.push_back(p); + push_back(p); } } p->addTotal(szsTotal, elsTotal); @@ -194,8 +199,8 @@ PidStatistics *n = (*it); if ((n->getPid() != n->gone) && (n->sizes() > l->sizes())) { pass = true; - Pids.erase(it); - Pids.insert(lt, n); + erase(it); + insert(lt, n); it = lt; n = l; } @@ -302,6 +307,10 @@ } void LidStatistics::subtract(unsigned short size, uid_t uid, pid_t pid) { + if (uid == (uid_t) -1) { // init + uid = (uid_t) AID_ROOT; + } + UidStatisticsCollection::iterator it; for (it = begin(); it != end(); ++it) { UidStatistics *u = *it; @@ -384,24 +393,25 @@ } LogStatistics::LogStatistics() - : start(CLOCK_MONOTONIC) { + : mStatistics(false) + , dgramQlenStatistics(false) + , start(CLOCK_MONOTONIC) { log_id_for_each(i) { mSizes[i] = 0; mElements[i] = 0; } - dgram_qlen_statistics = false; - for(unsigned short bucket = 0; dgram_qlen(bucket); ++bucket) { + for(unsigned short bucket = 0; dgramQlen(bucket); ++bucket) { mMinimum[bucket].tv_sec = mMinimum[bucket].tv_sec_max; mMinimum[bucket].tv_nsec = mMinimum[bucket].tv_nsec_max; } } -// Each bucket below represents a dgram_qlen of log messages. By +// Each bucket below represents a dgramQlen of log messages. By // finding the minimum period of time from start to finish -// of each dgram_qlen, we can get a performance expectation for +// of each dgramQlen, we can get a performance expectation for // the user space logger. The net result is that the period -// of time divided by the dgram_qlen will give us the average time +// of time divided by the dgramQlen will give us the average time // between log messages; at the point where the average time // is greater than the throughput capability of the logger // we will not longer require the benefits of the FIFO formed @@ -412,7 +422,7 @@ // // for example (reformatted): // -// Minimum time between log events per dgram_qlen: +// Minimum time between log events per dgramQlen: // 1 2 3 5 10 20 30 50 100 200 300 400 500 600 // 5u2 12u 13u 15u 16u 27u 30u 36u 407u 3m1 3m3 3m9 3m9 5m5 // @@ -426,12 +436,12 @@ // a large engineering margin so the rule of thumb that lead us to 100 is // fine. // -// bucket dgram_qlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300 +// bucket dgramQlen are tuned for /proc/sys/net/unix/max_dgram_qlen = 300 const unsigned short LogStatistics::mBuckets[] = { 1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 400, 500, 600 }; -unsigned short LogStatistics::dgram_qlen(unsigned short bucket) { +unsigned short LogStatistics::dgramQlen(unsigned short bucket) { if (bucket >= sizeof(mBuckets) / sizeof(mBuckets[0])) { return 0; } @@ -455,6 +465,9 @@ log_id_t log_id, uid_t uid, pid_t pid) { mSizes[log_id] += size; ++mElements[log_id]; + if (!mStatistics) { + return; + } id(log_id).add(size, uid, pid); } @@ -462,6 +475,9 @@ log_id_t log_id, uid_t uid, pid_t pid) { mSizes[log_id] -= size; --mElements[log_id]; + if (!mStatistics) { + return; + } id(log_id).subtract(size, uid, pid); } @@ -545,25 +561,28 @@ spaces = 1; log_time t(CLOCK_MONOTONIC); - unsigned long long d = t.nsec() - start.nsec(); - string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu", + unsigned long long d; + if (mStatistics) { + d = t.nsec() - start.nsec(); + string.appendFormat("\nTotal%4llu:%02llu:%02llu.%09llu", d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60, (d / NS_PER_SEC) % 60, d % NS_PER_SEC); - log_id_for_each(i) { - if (!(logMask & (1 << i))) { - continue; + log_id_for_each(i) { + if (!(logMask & (1 << i))) { + continue; + } + oldLength = string.length(); + if (spaces < 0) { + spaces = 0; + } + string.appendFormat("%*s%zu/%zu", spaces, "", + sizesTotal(i), elementsTotal(i)); + spaces += spaces_total + oldLength - string.length(); } - oldLength = string.length(); - if (spaces < 0) { - spaces = 0; - } - string.appendFormat("%*s%zu/%zu", spaces, "", - sizesTotal(i), elementsTotal(i)); - spaces += spaces_total + oldLength - string.length(); + spaces = 1; } - spaces = 1; d = t.nsec() - oldest.nsec(); string.appendFormat("\nNow%6llu:%02llu:%02llu.%09llu", d / NS_PER_SEC / 60 / 60, (d / NS_PER_SEC / 60) % 60, @@ -686,23 +705,23 @@ pids.clear(); } - if (dgram_qlen_statistics) { + if (dgramQlenStatistics) { const unsigned short spaces_time = 6; const unsigned long long max_seconds = 100000; spaces = 0; - string.append("\n\nMinimum time between log events per dgram_qlen:\n"); - for(unsigned short i = 0; dgram_qlen(i); ++i) { + string.append("\n\nMinimum time between log events per max_dgram_qlen:\n"); + for(unsigned short i = 0; dgramQlen(i); ++i) { oldLength = string.length(); if (spaces < 0) { spaces = 0; } - string.appendFormat("%*s%u", spaces, "", dgram_qlen(i)); + string.appendFormat("%*s%u", spaces, "", dgramQlen(i)); spaces += spaces_time + oldLength - string.length(); } string.append("\n"); spaces = 0; unsigned short n; - for(unsigned short i = 0; (n = dgram_qlen(i)); ++i) { + for(unsigned short i = 0; (n = dgramQlen(i)); ++i) { unsigned long long duration = minimum(i); if (duration) { duration /= n; @@ -724,8 +743,8 @@ / (NS_PER_SEC / 1000)); } else if (duration >= (NS_PER_SEC / (1000000 / 10))) { string.appendFormat("%lluu", - (duration + (NS_PER_SEC / 2 / 1000000)) - / (NS_PER_SEC / 1000000)); + (duration + (NS_PER_SEC / 2 / 1000000)) + / (NS_PER_SEC / 1000000)); } else { string.appendFormat("%llun", duration); }
diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h index 3733137..f6c4329 100644 --- a/logd/LogStatistics.h +++ b/logd/LogStatistics.h
@@ -72,6 +72,10 @@ PidStatisticsCollection Pids; + void insert(PidStatisticsCollection::iterator i, PidStatistics *p) + { Pids.insert(i, p); } + void push_back(PidStatistics *p) { Pids.push_back(p); } + size_t mSizes; size_t mElements; @@ -81,6 +85,8 @@ PidStatisticsCollection::iterator begin() { return Pids.begin(); } PidStatisticsCollection::iterator end() { return Pids.end(); } + PidStatisticsCollection::iterator erase(PidStatisticsCollection::iterator i) + { return Pids.erase(i); } uid_t getUid() { return uid; } @@ -138,7 +144,8 @@ size_t mSizes[LOG_ID_MAX]; size_t mElements[LOG_ID_MAX]; - bool dgram_qlen_statistics; + bool mStatistics; + bool dgramQlenStatistics; static const unsigned short mBuckets[14]; log_time mMinimum[sizeof(mBuckets) / sizeof(mBuckets[0])]; @@ -150,8 +157,9 @@ LidStatistics &id(log_id_t log_id) { return LogIds[log_id]; } - void enableDgramQlenStatistics() { dgram_qlen_statistics = true; } - static unsigned short dgram_qlen(unsigned short bucket); + void enableDgramQlenStatistics() { dgramQlenStatistics = true; } + void enableStatistics() { mStatistics = true; } + static unsigned short dgramQlen(unsigned short bucket); unsigned long long minimum(unsigned short bucket); void recordDiff(log_time diff, unsigned short bucket);
diff --git a/logd/README.property b/logd/README.property index f4b3c3c..b7fcece 100644 --- a/logd/README.property +++ b/logd/README.property
@@ -4,6 +4,9 @@ logd.auditd bool true Enable selinux audit daemon logd.auditd.dmesg bool true selinux audit messages duplicated and sent on to dmesg log +logd.statistics bool depends Enable logcat -S statistics. +ro.config.low_ram bool false if true, logd.statistics default false +ro.build.type string if user, logd.statistics default false logd.statistics.dgram_qlen bool false Record dgram_qlen statistics. This represents a performance impact and is used to determine the platform's
diff --git a/logd/libaudit.c b/logd/libaudit.c index ca88d1b..d00d579 100644 --- a/logd/libaudit.c +++ b/logd/libaudit.c
@@ -162,7 +162,7 @@ return rc; } -int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode) +int audit_setup(int fd, uint32_t pid) { int rc; struct audit_message rep; @@ -176,7 +176,8 @@ * and the the mask set to AUDIT_STATUS_PID */ status.pid = pid; - status.mask = AUDIT_STATUS_PID; + status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT; + status.rate_limit = 20; // audit entries per second /* Let the kernel know this pid will be registering for audit events */ rc = audit_send(fd, AUDIT_SET, &status, sizeof(status)); @@ -188,24 +189,21 @@ /* * In a request where we need to wait for a response, wait for the message * and discard it. This message confirms and sync's us with the kernel. - * This daemon is now registered as the audit logger. Only wait if the - * wmode is != WAIT_NO + * This daemon is now registered as the audit logger. + * + * TODO + * If the daemon dies and restarts the message didn't come back, + * so I went to non-blocking and it seemed to fix the bug. + * Need to investigate further. */ - if (wmode != WAIT_NO) { - /* TODO - * If the daemon dies and restarts the message didn't come back, - * so I went to non-blocking and it seemed to fix the bug. - * Need to investigate further. - */ - audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0); - } + audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0); return 0; } int audit_open() { - return socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT); + return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT); } int audit_get_reply(int fd, struct audit_message *rep, reply_t block, int peek)
diff --git a/logd/libaudit.h b/logd/libaudit.h index cb114f9..b9e330d 100644 --- a/logd/libaudit.h +++ b/logd/libaudit.h
@@ -37,11 +37,6 @@ GET_REPLY_NONBLOCKING } reply_t; -typedef enum { - WAIT_NO, - WAIT_YES -} rep_wait_t; - /* type == AUDIT_SIGNAL_INFO */ struct audit_sig_info { uid_t uid; @@ -92,12 +87,10 @@ * The fd returned by a call to audit_open() * @param pid * The pid whom to set as the reciever of audit messages - * @param wmode - * Whether or not to block on the underlying socket io calls. * @return * This function returns 0 on success, -errno on error. */ -extern int audit_set_pid(int fd, uint32_t pid, rep_wait_t wmode); +extern int audit_setup(int fd, uint32_t pid); __END_DECLS
diff --git a/logd/main.cpp b/logd/main.cpp index 1e1a718..54da7e3 100644 --- a/logd/main.cpp +++ b/logd/main.cpp
@@ -152,6 +152,15 @@ if (property_get_bool("logd.statistics.dgram_qlen", false)) { logBuf->enableDgramQlenStatistics(); } + { + char property[PROPERTY_VALUE_MAX]; + property_get("ro.build.type", property, ""); + if (property_get_bool("logd.statistics", + !!strcmp(property, "user") + && !property_get_bool("ro.config.low_ram", false))) { + logBuf->enableStatistics(); + } + } // LogReader listens on /dev/socket/logdr. When a client // connects, log entries in the LogBuffer are written to the client.
diff --git a/rootdir/init.environ.rc.in b/rootdir/init.environ.rc.in index 67222d7..30bef46 100644 --- a/rootdir/init.environ.rc.in +++ b/rootdir/init.environ.rc.in
@@ -10,4 +10,3 @@ export LOOP_MOUNTPOINT /mnt/obb export BOOTCLASSPATH %BOOTCLASSPATH% export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH% - export LD_PRELOAD libsigchain.so
diff --git a/rootdir/init.rc b/rootdir/init.rc index 9093b54..cbcb842 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc
@@ -119,25 +119,18 @@ mount cgroup none /dev/cpuctl cpu chown system system /dev/cpuctl chown system system /dev/cpuctl/tasks - chmod 0660 /dev/cpuctl/tasks + chmod 0666 /dev/cpuctl/tasks write /dev/cpuctl/cpu.shares 1024 - write /dev/cpuctl/cpu.rt_runtime_us 950000 + write /dev/cpuctl/cpu.rt_runtime_us 800000 write /dev/cpuctl/cpu.rt_period_us 1000000 - mkdir /dev/cpuctl/apps - chown system system /dev/cpuctl/apps/tasks - chmod 0666 /dev/cpuctl/apps/tasks - write /dev/cpuctl/apps/cpu.shares 1024 - write /dev/cpuctl/apps/cpu.rt_runtime_us 800000 - write /dev/cpuctl/apps/cpu.rt_period_us 1000000 - - mkdir /dev/cpuctl/apps/bg_non_interactive - chown system system /dev/cpuctl/apps/bg_non_interactive/tasks - chmod 0666 /dev/cpuctl/apps/bg_non_interactive/tasks + mkdir /dev/cpuctl/bg_non_interactive + chown system system /dev/cpuctl/bg_non_interactive/tasks + chmod 0666 /dev/cpuctl/bg_non_interactive/tasks # 5.0 % - write /dev/cpuctl/apps/bg_non_interactive/cpu.shares 52 - write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_runtime_us 700000 - write /dev/cpuctl/apps/bg_non_interactive/cpu.rt_period_us 1000000 + write /dev/cpuctl/bg_non_interactive/cpu.shares 52 + write /dev/cpuctl/bg_non_interactive/cpu.rt_runtime_us 700000 + write /dev/cpuctl/bg_non_interactive/cpu.rt_period_us 1000000 # qtaguid will limit access to specific data based on group memberships. # net_bw_acct grants impersonation of socket owners.
diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc index eff24c3..474f630 100644 --- a/rootdir/ueventd.rc +++ b/rootdir/ueventd.rc
@@ -88,6 +88,7 @@ /dev/ppp 0660 radio vpn # sysfs properties +/sys/devices/platform/trusty.* trusty_version 0440 root log /sys/devices/virtual/input/input* enable 0660 root input /sys/devices/virtual/input/input* poll_delay 0660 root input /sys/devices/virtual/usb_composite/* enable 0664 root system
diff --git a/sdcard/sdcard.c b/sdcard/sdcard.c index 7bf6394..9cfb040 100644 --- a/sdcard/sdcard.c +++ b/sdcard/sdcard.c
@@ -168,6 +168,11 @@ __u32 refcount; __u64 nid; __u64 gen; + /* + * The inode number for this FUSE node. Note that this isn't stable across + * multiple invocations of the FUSE daemon. + */ + __u32 ino; /* State derived based on current position in hierarchy. */ perm_t perm; @@ -224,6 +229,25 @@ struct node root; char obbpath[PATH_MAX]; + /* Used to allocate unique inode numbers for fuse nodes. We use + * a simple counter based scheme where inode numbers from deleted + * nodes aren't reused. Note that inode allocations are not stable + * across multiple invocation of the sdcard daemon, but that shouldn't + * be a huge problem in practice. + * + * Note that we restrict inodes to 32 bit unsigned integers to prevent + * truncation on 32 bit processes when unsigned long long stat.st_ino is + * assigned to an unsigned long ino_t type in an LP32 process. + * + * Also note that fuse_attr and fuse_dirent inode values are 64 bits wide + * on both LP32 and LP64, but the fuse kernel code doesn't squash 64 bit + * inode numbers into 32 bit values on 64 bit kernels (see fuse_squash_ino + * in fs/fuse/inode.c). + * + * Accesses must be guarded by |lock|. + */ + __u32 inode_ctr; + Hashmap* package_to_appid; Hashmap* appid_with_rw; }; @@ -387,7 +411,7 @@ static void attr_from_stat(struct fuse_attr *attr, const struct stat *s, const struct node* node) { - attr->ino = node->nid; + attr->ino = node->ino; attr->size = s->st_size; attr->blocks = s->st_blocks; attr->atime = s->st_atime; @@ -575,6 +599,13 @@ struct node *node; size_t namelen = strlen(name); + // Detect overflows in the inode counter. "4 billion nodes should be enough + // for everybody". + if (fuse->inode_ctr == 0) { + ERROR("No more inode numbers available"); + return NULL; + } + node = calloc(1, sizeof(struct node)); if (!node) { return NULL; @@ -596,6 +627,7 @@ } node->namelen = namelen; node->nid = ptr_to_id(node); + node->ino = fuse->inode_ctr++; node->gen = fuse->next_generation++; derive_permissions_locked(fuse, parent, node); @@ -700,6 +732,7 @@ fuse->derive = derive; fuse->split_perms = split_perms; fuse->write_gid = write_gid; + fuse->inode_ctr = 1; memset(&fuse->root, 0, sizeof(fuse->root)); fuse->root.nid = FUSE_ROOT_ID; /* 1 */ @@ -1807,7 +1840,7 @@ "fd=%i,rootmode=40000,default_permissions,allow_other,user_id=%d,group_id=%d", fd, uid, gid); - res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV, opts); + res = mount("/dev/fuse", dest_path, "fuse", MS_NOSUID | MS_NODEV | MS_NOEXEC, opts); if (res < 0) { ERROR("cannot mount fuse filesystem: %s\n", strerror(errno)); goto error;
diff --git a/toolbox/Android.mk b/toolbox/Android.mk index d8d397e..84714cf 100644 --- a/toolbox/Android.mk +++ b/toolbox/Android.mk
@@ -176,6 +176,7 @@ readlink \ renice \ restorecon \ + prlimit \ rmmod \ route \ runcon \
diff --git a/toolbox/prlimit.c b/toolbox/prlimit.c new file mode 100644 index 0000000..8cf202a --- /dev/null +++ b/toolbox/prlimit.c
@@ -0,0 +1,76 @@ +/* + * Copyright (c) 2014, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google, Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/resource.h> + +static void +usage(const char *s) +{ + fprintf(stderr, "usage: %s pid resource cur max\n", s); + exit(EXIT_FAILURE); +} + +int prlimit_main(int argc, char *argv[]) +{ + pid_t pid; + struct rlimit64 rl; + int resource; + int rc; + + if (argc != 5) + usage(*argv); + + if (sscanf(argv[1], "%d", &pid) != 1) + usage(*argv); + + if (sscanf(argv[2], "%d", &resource) != 1) + usage(*argv); + + if (sscanf(argv[3], "%llu", &rl.rlim_cur) != 1) + usage(*argv); + + if (sscanf(argv[4], "%llu", &rl.rlim_max) != 1) + usage(*argv); + + printf("setting resource %d of pid %d to [%llu,%llu]\n", resource, pid, + rl.rlim_cur, rl.rlim_max); + rc = prlimit64(pid, resource, &rl, NULL); + if (rc < 0) { + perror("prlimit"); + exit(EXIT_FAILURE); + } + + return 0; +}
diff --git a/toolbox/top.c b/toolbox/top.c index 280a032..b1a275c 100644 --- a/toolbox/top.c +++ b/toolbox/top.c
@@ -32,6 +32,7 @@ #include <ctype.h> #include <dirent.h> #include <grp.h> +#include <inttypes.h> #include <pwd.h> #include <stdio.h> #include <stdlib.h> @@ -59,13 +60,13 @@ char name[PROC_NAME_LEN]; char tname[THREAD_NAME_LEN]; char state; - long unsigned utime; - long unsigned stime; - long unsigned delta_utime; - long unsigned delta_stime; - long unsigned delta_time; - long vss; - long rss; + uint64_t utime; + uint64_t stime; + uint64_t delta_utime; + uint64_t delta_stime; + uint64_t delta_time; + uint64_t vss; + uint64_t rss; int prs; int num_threads; char policy[POLICY_NAME_LEN]; @@ -344,10 +345,19 @@ proc->tname[THREAD_NAME_LEN-1] = 0; /* Scan rest of string. */ - sscanf(close_paren + 1, " %c %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " - "%lu %lu %*d %*d %*d %*d %*d %*d %*d %lu %ld " - "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %d", - &proc->state, &proc->utime, &proc->stime, &proc->vss, &proc->rss, &proc->prs); + sscanf(close_paren + 1, + " %c " "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " + "%" SCNu64 + "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d " + "%" SCNu64 + "%" SCNu64 "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " + "%d", + &proc->state, + &proc->utime, + &proc->stime, + &proc->vss, + &proc->rss, + &proc->prs); return 0; } @@ -470,12 +480,15 @@ snprintf(user_buf, 20, "%d", proc->uid); user_str = user_buf; } - if (!threads) - printf("%5d %2d %3ld%% %c %5d %6ldK %6ldK %3s %-8.8s %s\n", proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads, - proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname); - else - printf("%5d %5d %2d %3ld%% %c %6ldK %6ldK %3s %-8.8s %-15s %s\n", proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, - proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name); + if (!threads) { + printf("%5d %2d %3" PRIu64 "%% %c %5d %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %s\n", + proc->pid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, proc->num_threads, + proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->name[0] != 0 ? proc->name : proc->tname); + } else { + printf("%5d %5d %2d %3" PRIu64 "%% %c %6" PRIu64 "K %6" PRIu64 "K %3s %-8.8s %-15s %s\n", + proc->pid, proc->tid, proc->prs, proc->delta_time * 100 / total_delta_time, proc->state, + proc->vss / 1024, proc->rss * getpagesize() / 1024, proc->policy, user_str, proc->tname, proc->name); + } } }