diff --git a/adb/Android.mk b/adb/Android.mk index 36b67b2e6..627148365 100644 --- a/adb/Android.mk +++ b/adb/Android.mk @@ -113,6 +113,7 @@ LOCAL_SRC_FILES := \ jdwp_service.c \ framebuffer_service.c \ remount_service.c \ + disable_verity_service.c \ usb_linux_client.c LOCAL_CFLAGS := \ @@ -127,14 +128,26 @@ ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT))) 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 \ + libfs_mgr \ + libcutils \ + libc \ + libmincrypt \ + libselinux \ + libext4_utils_static LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk -LOCAL_STATIC_LIBRARIES := liblog libcutils libc libmincrypt libselinux include $(BUILD_EXECUTABLE) diff --git a/adb/adb.h b/adb/adb.h index 4f068000a..44e5981bd 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -329,6 +329,7 @@ int handle_forward_request(const char* service, transport_type ttype, char* seri #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/commandline.c b/adb/commandline.c index 05b4ef6fc..87baeb909 100644 --- a/adb/commandline.c +++ b/adb/commandline.c @@ -189,6 +189,7 @@ void help() "\n" " adb restore - restore device contents from the backup archive\n" "\n" + " adb disable-verity - disable dm-verity checking on USERDEBUG builds\n" " adb help - show this help message\n" " adb version - show version num\n" "\n" @@ -205,8 +206,7 @@ void help() " 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 - restarts the adbd daemon listening on TCP on the specified port" - "\n" + " adb tcpip - restarts the adbd daemon listening on TCP on the specified port\n" "networking:\n" " adb ppp [parameters] - Run PPP over USB.\n" " Note: you should not automatically start a PPP connection.\n" @@ -1437,7 +1437,7 @@ top: 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"); diff --git a/adb/disable_verity_service.c b/adb/disable_verity_service.c new file mode 100644 index 000000000..ed3da5210 --- /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 +#include +#include +#include +#include + +#include "cutils/properties.h" +#include "ext4_sb.h" +#include + +#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/services.c b/adb/services.c index e61371ab1..21b08dc20 100644 --- a/adb/services.c +++ b/adb/services.c @@ -469,6 +469,8 @@ int service_to_fd(const char *name) free(cookie); } } + } else if(!strncmp(name, "disable-verity:", 15)) { + ret = create_service_thread(disable_verity_service, NULL); #endif } if (ret >= 0) { diff --git a/fs_mgr/Android.mk b/fs_mgr/Android.mk index 7cffc37a5..61bf1ee6a 100644 --- a/fs_mgr/Android.mk +++ b/fs_mgr/Android.mk @@ -13,6 +13,10 @@ LOCAL_C_INCLUDES += system/extras/ext4_utils 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) diff --git a/fs_mgr/fs_mgr.c b/fs_mgr/fs_mgr.c index 91e6c3326..40878c1f6 100644 --- a/fs_mgr/fs_mgr.c +++ b/fs_mgr/fs_mgr.c @@ -245,6 +245,16 @@ static int device_is_debuggable() { 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; +} + /* * Tries to mount any of the consecutive fstab entries that match * the mountpoint of the one given by fstab->recs[start_idx]. @@ -350,9 +360,11 @@ int fs_mgr_mount_all(struct fstab *fstab) 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; } @@ -467,9 +479,11 @@ int fs_mgr_do_mount(struct fstab *fstab, char *n_name, char *n_blk_device, 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_fstab.c b/fs_mgr/fs_mgr_fstab.c index 3f841792c..ab8f128ce 100644 --- a/fs_mgr/fs_mgr_fstab.c +++ b/fs_mgr/fs_mgr_fstab.c @@ -418,6 +418,11 @@ int fs_mgr_is_nonremovable(struct fstab_rec *fstab) 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); diff --git a/fs_mgr/fs_mgr_priv_verity.h b/fs_mgr/fs_mgr_priv_verity.h index 61937849a..f90e59683 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 da3c0f91a..39f96a7a2 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; @@ -157,7 +156,9 @@ static int read_verity_metadata(char *block_device, char **signature, char **tab uint64_t device_length; int protocol_version; FILE *device; - int retval = -1; + int retval = FS_MGR_SETUP_VERITY_FAIL; + *signature = 0; + *table = 0; device = fopen(block_device, "r"); if (!device) { @@ -180,8 +181,18 @@ static int read_verity_metadata(char *block_device, char **signature, char **tab 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; } @@ -203,14 +214,12 @@ static int read_verity_metadata(char *block_device, char **signature, char **tab } if (!fread(*signature, RSANUMBYTES, 1, device)) { 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)) { ERROR("Couldn't get the size of the verity table from metadata!\n"); - free(*signature); goto out; } @@ -223,16 +232,22 @@ static int read_verity_metadata(char *block_device, char **signature, char **tab } if (!fgets(*table, table_length, device)) { ERROR("Couldn't read the verity table from metadata!\n"); - free(*table); - free(*signature); goto out; } - retval = 0; + retval = FS_MGR_SETUP_VERITY_SUCCESS; out: if (device) fclose(device); + + if (retval != FS_MGR_SETUP_VERITY_SUCCESS) { + free(*table); + free(*signature); + *table = 0; + *signature = 0; + } + return retval; } @@ -360,10 +375,11 @@ static int set_verified_property(char *name) { int fs_mgr_setup_verity(struct fstab_rec *fstab) { int retval = -1; + 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; @@ -380,11 +396,19 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { 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; + } + // 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 @@ -399,13 +423,6 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { 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, @@ -426,6 +443,7 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { // 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) { @@ -436,6 +454,13 @@ int fs_mgr_setup_verity(struct fstab_rec *fstab) { 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 0c7eb20d2..5e2ff416a 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -20,6 +20,13 @@ #include #include +// 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,6 +81,7 @@ int fs_mgr_add_entry(struct fstab *fstab, 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_swapon_all(struct fstab *fstab);