Merge "fs_mgr_verity: Add support for squashfs"
diff --git a/adb/remount_service.cpp b/adb/remount_service.cpp
index 483ca3d..b150274 100644
--- a/adb/remount_service.cpp
+++ b/adb/remount_service.cpp
@@ -112,13 +112,13 @@
     }
 
     bool system_verified = false, vendor_verified = false;
-    property_get("partition.system.verified", prop_buf, "0");
-    if (!strcmp(prop_buf, "1")) {
+    property_get("partition.system.verified", prop_buf, "");
+    if (strlen(prop_buf) > 0) {
         system_verified = true;
     }
 
-    property_get("partition.vendor.verified", prop_buf, "0");
-    if (!strcmp(prop_buf, "1")) {
+    property_get("partition.vendor.verified", prop_buf, "");
+    if (strlen(prop_buf) > 0) {
         vendor_verified = true;
     }
 
diff --git a/fs_mgr/fs_mgr_verity.c b/fs_mgr/fs_mgr_verity.c
index 840cf5a..c457762 100644
--- a/fs_mgr/fs_mgr_verity.c
+++ b/fs_mgr/fs_mgr_verity.c
@@ -52,6 +52,8 @@
 #define METADATA_TAG_MAX_LENGTH 63
 #define METADATA_EOD "eod"
 
+#define VERITY_LASTSIG_TAG "verity_lastsig"
+
 #define VERITY_STATE_TAG "verity_state"
 #define VERITY_STATE_HEADER 0x83c0ae9d
 #define VERITY_STATE_VERSION 1
@@ -192,8 +194,12 @@
     int protocol_version;
     int device;
     int retval = FS_MGR_SETUP_VERITY_FAIL;
-    *signature = 0;
-    *table = 0;
+
+    *signature = NULL;
+
+    if (table) {
+        *table = NULL;
+    }
 
     device = TEMP_FAILURE_RETRY(open(block_device, O_RDONLY | O_CLOEXEC));
     if (device == -1) {
@@ -248,6 +254,11 @@
         goto out;
     }
 
+    if (!table) {
+        retval = FS_MGR_SETUP_VERITY_SUCCESS;
+        goto out;
+    }
+
     // get the size of the table
     if (TEMP_FAILURE_RETRY(read(device, &table_length, sizeof(table_length))) !=
             sizeof(table_length)) {
@@ -275,10 +286,13 @@
         TEMP_FAILURE_RETRY(close(device));
 
     if (retval != FS_MGR_SETUP_VERITY_SUCCESS) {
-        free(*table);
         free(*signature);
-        *table = 0;
-        *signature = 0;
+        *signature = NULL;
+
+        if (table) {
+            free(*table);
+            *table = NULL;
+        }
     }
 
     return retval;
@@ -596,46 +610,29 @@
     return rc;
 }
 
-static int load_verity_state(struct fstab_rec *fstab, int *mode)
+static int read_verity_state(const char *fname, off64_t offset, int *mode)
 {
     int fd = -1;
     int rc = -1;
-    off64_t offset = 0;
     struct verity_state s;
 
-    if (metadata_find(fstab->verity_loc, VERITY_STATE_TAG, sizeof(s),
-            &offset) < 0) {
-        /* fall back to stateless behavior */
-        *mode = VERITY_MODE_EIO;
-        rc = 0;
-        goto out;
-    }
-
-    if (was_verity_restart()) {
-        /* device was restarted after dm-verity detected a corrupted
-         * block, so switch to logging mode */
-        *mode = VERITY_MODE_LOGGING;
-        rc = write_verity_state(fstab->verity_loc, offset, *mode);
-        goto out;
-    }
-
-    fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDONLY | O_CLOEXEC));
+    fd = TEMP_FAILURE_RETRY(open(fname, O_RDONLY | O_CLOEXEC));
 
     if (fd == -1) {
-        ERROR("Failed to open %s (%s)\n", fstab->verity_loc, strerror(errno));
+        ERROR("Failed to open %s (%s)\n", fname, strerror(errno));
         goto out;
     }
 
     if (TEMP_FAILURE_RETRY(pread64(fd, &s, sizeof(s), offset)) != sizeof(s)) {
         ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n",
-            sizeof(s), fstab->verity_loc, offset, strerror(errno));
+            sizeof(s), fname, offset, strerror(errno));
         goto out;
     }
 
     if (s.header != VERITY_STATE_HEADER) {
         /* space allocated, but no state written. write default state */
         *mode = VERITY_MODE_DEFAULT;
-        rc = write_verity_state(fstab->verity_loc, offset, *mode);
+        rc = write_verity_state(fname, offset, *mode);
         goto out;
     }
 
@@ -661,14 +658,126 @@
     return rc;
 }
 
+static int compare_last_signature(struct fstab_rec *fstab, int *match)
+{
+    char tag[METADATA_TAG_MAX_LENGTH + 1];
+    char *signature = NULL;
+    int fd = -1;
+    int rc = -1;
+    uint8_t curr[SHA256_DIGEST_SIZE];
+    uint8_t prev[SHA256_DIGEST_SIZE];
+    off64_t offset = 0;
+
+    *match = 1;
+
+    if (read_verity_metadata(fstab->blk_device, &signature, NULL) < 0) {
+        ERROR("Failed to read verity signature from %s\n", fstab->mount_point);
+        goto out;
+    }
+
+    SHA256_hash(signature, RSANUMBYTES, curr);
+
+    if (snprintf(tag, sizeof(tag), VERITY_LASTSIG_TAG "_%s",
+            basename(fstab->mount_point)) >= (int)sizeof(tag)) {
+        ERROR("Metadata tag name too long for %s\n", fstab->mount_point);
+        goto out;
+    }
+
+    if (metadata_find(fstab->verity_loc, tag, SHA256_DIGEST_SIZE,
+            &offset) < 0) {
+        goto out;
+    }
+
+    fd = TEMP_FAILURE_RETRY(open(fstab->verity_loc, O_RDWR | O_SYNC | O_CLOEXEC));
+
+    if (fd == -1) {
+        ERROR("Failed to open %s: %s\n", fstab->verity_loc, strerror(errno));
+        goto out;
+    }
+
+    if (TEMP_FAILURE_RETRY(pread64(fd, prev, sizeof(prev),
+            offset)) != sizeof(prev)) {
+        ERROR("Failed to read %zu bytes from %s offset %" PRIu64 " (%s)\n",
+            sizeof(prev), fstab->verity_loc, offset, strerror(errno));
+        goto out;
+    }
+
+    *match = !memcmp(curr, prev, SHA256_DIGEST_SIZE);
+
+    if (!*match) {
+        /* update current signature hash */
+        if (TEMP_FAILURE_RETRY(pwrite64(fd, curr, sizeof(curr),
+                offset)) != sizeof(curr)) {
+            ERROR("Failed to write %zu bytes to %s offset %" PRIu64 " (%s)\n",
+                sizeof(curr), fstab->verity_loc, offset, strerror(errno));
+            goto out;
+        }
+    }
+
+    rc = 0;
+
+out:
+    free(signature);
+
+    if (fd != -1) {
+        TEMP_FAILURE_RETRY(close(fd));
+    }
+
+    return rc;
+}
+
+static int get_verity_state_offset(struct fstab_rec *fstab, off64_t *offset)
+{
+    char tag[METADATA_TAG_MAX_LENGTH + 1];
+
+    if (snprintf(tag, sizeof(tag), VERITY_STATE_TAG "_%s",
+            basename(fstab->mount_point)) >= (int)sizeof(tag)) {
+        ERROR("Metadata tag name too long for %s\n", fstab->mount_point);
+        return -1;
+    }
+
+    return metadata_find(fstab->verity_loc, tag, sizeof(struct verity_state),
+                offset);
+}
+
+static int load_verity_state(struct fstab_rec *fstab, int *mode)
+{
+    off64_t offset = 0;
+    int match = 0;
+
+    if (get_verity_state_offset(fstab, &offset) < 0) {
+        /* fall back to stateless behavior */
+        *mode = VERITY_MODE_EIO;
+        return 0;
+    }
+
+    if (was_verity_restart()) {
+        /* device was restarted after dm-verity detected a corrupted
+         * block, so switch to logging mode */
+        *mode = VERITY_MODE_LOGGING;
+        return write_verity_state(fstab->verity_loc, offset, *mode);
+    }
+
+    if (!compare_last_signature(fstab, &match) && !match) {
+        /* partition has been reflashed, reset dm-verity state */
+        *mode = VERITY_MODE_DEFAULT;
+        return write_verity_state(fstab->verity_loc, offset, *mode);
+    }
+
+    return read_verity_state(fstab->verity_loc, offset, mode);
+}
+
 int fs_mgr_load_verity_state(int *mode)
 {
     char fstab_filename[PROPERTY_VALUE_MAX + sizeof(FSTAB_PREFIX)];
     char propbuf[PROPERTY_VALUE_MAX];
     int rc = -1;
     int i;
+    int current;
     struct fstab *fstab = NULL;
 
+    /* return the default mode, unless any of the verified partitions are in
+     * logging mode, in which case return that */
     *mode = VERITY_MODE_DEFAULT;
 
     property_get("ro.hardware", propbuf, "");
@@ -686,20 +795,16 @@
             continue;
         }
 
-        rc = load_verity_state(&fstab->recs[i], mode);
+        rc = load_verity_state(&fstab->recs[i], &current);
         if (rc < 0) {
             continue;
         }
 
-        /* if any of the verified partitions are in logging mode, return */
-        if (*mode == VERITY_MODE_LOGGING) {
-            rc = 0;
-            goto out;
+        if (current == VERITY_MODE_LOGGING) {
+            *mode = current;
         }
     }
 
-    /* if there were multiple partitions, all in non-logging mode, return the
-     * state of the last one */
     rc = 0;
 
 out:
@@ -719,6 +824,7 @@
     char *status;
     int fd = -1;
     int i;
+    int mode;
     int rc = -1;
     off64_t offset = 0;
     struct dm_ioctl *io = (struct dm_ioctl *) buffer;
@@ -746,8 +852,8 @@
             continue;
         }
 
-        if (metadata_find(fstab->recs[i].verity_loc, VERITY_STATE_TAG,
-                sizeof(struct verity_state), &offset) < 0) {
+        if (get_verity_state_offset(&fstab->recs[i], &offset) < 0 ||
+            read_verity_state(fstab->recs[i].verity_loc, offset, &mode) < 0) {
             continue;
         }
 
@@ -757,26 +863,23 @@
         if (ioctl(fd, DM_TABLE_STATUS, io)) {
             ERROR("Failed to query DM_TABLE_STATUS for %s (%s)\n", mount_point,
                 strerror(errno));
-            goto out;
+            continue;
         }
 
         status = &buffer[io->data_start + sizeof(struct dm_target_spec)];
 
         if (*status == 'C') {
-            rc = write_verity_state(fstab->recs[i].verity_loc, offset,
-                    VERITY_MODE_LOGGING);
-
-            if (rc == -1) {
-                goto out;
+            if (write_verity_state(fstab->recs[i].verity_loc, offset,
+                    VERITY_MODE_LOGGING) < 0) {
+                continue;
             }
         }
 
         if (callback) {
-            callback(&fstab->recs[i], mount_point, *status);
+            callback(&fstab->recs[i], mount_point, mode, *status);
         }
     }
 
-    /* Don't overwrite possible previous state if there's no corruption. */
     rc = 0;
 
 out:
diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h
index b5e02f9..c58a888 100644
--- a/fs_mgr/include/fs_mgr.h
+++ b/fs_mgr/include/fs_mgr.h
@@ -69,7 +69,7 @@
 
 // Callback function for verity status
 typedef void (*fs_mgr_verity_state_callback)(struct fstab_rec *fstab,
-        const char *mount_point, int status);
+        const char *mount_point, int mode, int status);
 
 struct fstab *fs_mgr_read_fstab(const char *fstab_path);
 void fs_mgr_free_fstab(struct fstab *fstab);
diff --git a/include/private/android_logger.h b/include/private/android_logger.h
index 724ca51..04238a6 100644
--- a/include/private/android_logger.h
+++ b/include/private/android_logger.h
@@ -70,7 +70,17 @@
     android_event_long_t payload;
 } android_log_event_long_t;
 
-/* Event payload EVENT_TYPE_STRING */
+/*
+ * Event payload EVENT_TYPE_STRING
+ *
+ * Danger: do not embed this structure into another structure.
+ * This structure uses a flexible array member, and when
+ * compiled using g++, __builtin_object_size(data, 1) returns
+ * a bad value. This is possibly a g++ bug, or a bug due to
+ * the fact that flexible array members are not supported
+ * in C++.
+ * http://stackoverflow.com/questions/4412749/are-flexible-array-members-valid-in-c
+ */
 typedef struct __attribute__((__packed__)) {
     int8_t type;    // EVENT_TYPE_STRING;
     int32_t length; // Little Endian Order
@@ -80,7 +90,9 @@
 /* Event with single EVENT_TYPE_STRING */
 typedef struct __attribute__((__packed__)) {
     android_event_header_t header;
-    android_event_string_t payload;
+    int8_t type;    // EVENT_TYPE_STRING;
+    int32_t length; // Little Endian Order
+    char data[];
 } android_log_event_string_t;
 
 #endif
diff --git a/init/builtins.cpp b/init/builtins.cpp
index ff6c937..3bbaf83 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -661,8 +661,9 @@
     return rc;
 }
 
-static void verity_update_property(fstab_rec *fstab, const char *mount_point, int status) {
-    property_set(android::base::StringPrintf("partition.%s.verified", mount_point).c_str(), "1");
+static void verity_update_property(fstab_rec *fstab, const char *mount_point, int mode, int status) {
+    property_set(android::base::StringPrintf("partition.%s.verified", mount_point).c_str(),
+                 android::base::StringPrintf("%d", mode).c_str());
 }
 
 int do_verity_update_state(int nargs, char** args) {
diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp
index 6b3e637..bdb2915 100644
--- a/logd/LogAudit.cpp
+++ b/logd/LogAudit.cpp
@@ -150,9 +150,9 @@
         rc = -ENOMEM;
     } else {
         event->header.tag = htole32(AUDITD_LOG_TAG);
-        event->payload.type = EVENT_TYPE_STRING;
-        event->payload.length = htole32(l);
-        memcpy(event->payload.data, str, l);
+        event->type = EVENT_TYPE_STRING;
+        event->length = htole32(l);
+        memcpy(event->data, str, l);
 
         logbuf->log(LOG_ID_EVENTS, now, uid, pid, tid,
                     reinterpret_cast<char *>(event),
diff --git a/rootdir/init.rc b/rootdir/init.rc
index cda79ce..e6f4f4a 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -188,6 +188,7 @@
 
 
 on post-fs
+    start logd
     # once everything is setup, no need to modify /
     mount rootfs rootfs / ro remount
     # mount shared so changes propagate into child namespaces
@@ -311,6 +312,7 @@
     mkdir /data/media 0770 media_rw media_rw
     mkdir /data/ss 0700 system system
     mkdir /data/system 0775 system system
+    mkdir /data/system/heapdump 0700 system system
     mkdir /data/user 0711 system system
 
     # Reload policy from /data/security if present.
@@ -484,6 +486,7 @@
     socket logdw dgram 0222 logd logd
 
 service logd-reinit /system/bin/logd --reinit
+    start logd
     oneshot
     disabled
 
diff --git a/toolbox/Android.mk b/toolbox/Android.mk
index 186a89f..6f5567d 100644
--- a/toolbox/Android.mk
+++ b/toolbox/Android.mk
@@ -41,7 +41,6 @@
 OUR_TOOLS := \
     df \
     getevent \
-    getprop \
     iftop \
     ioctl \
     ionice \
@@ -54,9 +53,7 @@
     ps \
     prlimit \
     renice \
-    restorecon \
     sendevent \
-    setprop \
     start \
     stop \
     top \
diff --git a/toolbox/getprop.c b/toolbox/getprop.c
deleted file mode 100644
index dcc0ea0..0000000
--- a/toolbox/getprop.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <cutils/properties.h>
-
-#include "dynarray.h"
-
-static void record_prop(const char* key, const char* name, void* opaque)
-{
-    strlist_t* list = opaque;
-    char temp[PROP_VALUE_MAX + PROP_NAME_MAX + 16];
-    snprintf(temp, sizeof temp, "[%s]: [%s]", key, name);
-    strlist_append_dup(list, temp);
-}
-
-static void list_properties(void)
-{
-    strlist_t  list[1] = { STRLIST_INITIALIZER };
-
-    /* Record properties in the string list */
-    (void)property_list(record_prop, list);
-
-    /* Sort everything */
-    strlist_sort(list);
-
-    /* print everything */
-    STRLIST_FOREACH(list, str, printf("%s\n", str));
-
-    /* voila */
-    strlist_done(list);
-}
-
-int getprop_main(int argc, char *argv[])
-{
-    if (argc == 1) {
-        list_properties();
-    } else {
-        char value[PROPERTY_VALUE_MAX];
-        char *default_value;
-        if(argc > 2) {
-            default_value = argv[2];
-        } else {
-            default_value = "";
-        }
-
-        property_get(argv[1], value, default_value);
-        printf("%s\n", value);
-    }
-    return 0;
-}
diff --git a/toolbox/restorecon.c b/toolbox/restorecon.c
deleted file mode 100644
index cb5799e..0000000
--- a/toolbox/restorecon.c
+++ /dev/null
@@ -1,63 +0,0 @@
-#include <unistd.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-#include <selinux/android.h>
-
-static const char *progname;
-
-static void usage(void)
-{
-    fprintf(stderr, "usage:  %s [-DFnrRv] pathname...\n", progname);
-    exit(1);
-}
-
-int restorecon_main(int argc, char **argv)
-{
-    int ch, i, rc;
-    unsigned int flags = 0;
-
-    progname = argv[0];
-
-    do {
-        ch = getopt(argc, argv, "DFnrRv");
-        if (ch == EOF)
-            break;
-        switch (ch) {
-        case 'D':
-            flags |= SELINUX_ANDROID_RESTORECON_DATADATA;
-            break;
-        case 'F':
-            flags |= SELINUX_ANDROID_RESTORECON_FORCE;
-            break;
-        case 'n':
-            flags |= SELINUX_ANDROID_RESTORECON_NOCHANGE;
-            break;
-        case 'r':
-        case 'R':
-            flags |= SELINUX_ANDROID_RESTORECON_RECURSE;
-            break;
-        case 'v':
-            flags |= SELINUX_ANDROID_RESTORECON_VERBOSE;
-            break;
-        default:
-            usage();
-        }
-    } while (1);
-
-    argc -= optind;
-    argv += optind;
-    if (!argc)
-        usage();
-
-    for (i = 0; i < argc; i++) {
-        rc = selinux_android_restorecon(argv[i], flags);
-        if (rc < 0)
-            fprintf(stderr, "Could not restorecon %s:  %s\n", argv[i],
-                    strerror(errno));
-    }
-
-    return 0;
-}
diff --git a/toolbox/setprop.c b/toolbox/setprop.c
deleted file mode 100644
index 63ad2b4..0000000
--- a/toolbox/setprop.c
+++ /dev/null
@@ -1,18 +0,0 @@
-#include <stdio.h>
-
-#include <cutils/properties.h>
-
-int setprop_main(int argc, char *argv[])
-{
-    if(argc != 3) {
-        fprintf(stderr,"usage: setprop <key> <value>\n");
-        return 1;
-    }
-
-    if(property_set(argv[1], argv[2])){
-        fprintf(stderr,"could not set property\n");
-        return 1;
-    }
-
-    return 0;
-}