From bac7fba02763ae5e78e8e4ba0bea727330ad953e Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Wed, 10 Apr 2013 11:32:17 -0700 Subject: verifier: update to support certificates using SHA-256 Change-Id: Ifd5a29d459acf101311fa1c220f728c3d0ac2e4e --- applypatch/applypatch.c | 2 +- install.cpp | 2 +- testdata/otasigned_f4_sha256.zip | Bin 0 -> 5319 bytes testdata/otasigned_sha256.zip | Bin 0 -> 5326 bytes testdata/test_f4_sha256.x509.pem | 25 +++++++ testdata/testkey.pk8 | Bin 0 -> 1217 bytes testdata/testkey.x509.pem | 27 +++++++ testdata/testkey_sha256.x509.pem | 27 +++++++ updater/install.c | 2 +- verifier.cpp | 80 ++++++++++++++++----- verifier.h | 9 ++- verifier_test.cpp | 151 +++++++++++++++++++++------------------ verifier_test.sh | 38 +++++----- 13 files changed, 254 insertions(+), 109 deletions(-) create mode 100644 testdata/otasigned_f4_sha256.zip create mode 100644 testdata/otasigned_sha256.zip create mode 100644 testdata/test_f4_sha256.x509.pem create mode 100644 testdata/testkey.pk8 create mode 100644 testdata/testkey.x509.pem create mode 100644 testdata/testkey_sha256.x509.pem diff --git a/applypatch/applypatch.c b/applypatch/applypatch.c index 69f8633ab..259fa581e 100644 --- a/applypatch/applypatch.c +++ b/applypatch/applypatch.c @@ -101,7 +101,7 @@ int LoadFileContents(const char* filename, FileContents* file, } } - SHA(file->data, file->size, file->sha1); + SHA_hash(file->data, file->size, file->sha1); return 0; } diff --git a/install.cpp b/install.cpp index 0f3298f1d..0cb5cc7df 100644 --- a/install.cpp +++ b/install.cpp @@ -190,7 +190,7 @@ really_install_package(const char *path, int* wipe_cache) ui->Print("Opening update package...\n"); int numKeys; - RSAPublicKey* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys); + Certificate* loadedKeys = load_keys(PUBLIC_KEYS_FILE, &numKeys); if (loadedKeys == NULL) { LOGE("Failed to load keys\n"); return INSTALL_CORRUPT; diff --git a/testdata/otasigned_f4_sha256.zip b/testdata/otasigned_f4_sha256.zip new file mode 100644 index 000000000..3af408c40 Binary files /dev/null and b/testdata/otasigned_f4_sha256.zip differ diff --git a/testdata/otasigned_sha256.zip b/testdata/otasigned_sha256.zip new file mode 100644 index 000000000..0ed4409b3 Binary files /dev/null and b/testdata/otasigned_sha256.zip differ diff --git a/testdata/test_f4_sha256.x509.pem b/testdata/test_f4_sha256.x509.pem new file mode 100644 index 000000000..9d5376b45 --- /dev/null +++ b/testdata/test_f4_sha256.x509.pem @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIJAKhkCO1dDYMaMA0GCSqGSIb3DQEBCwUAMG8xCzAJBgNV +BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBW +aWV3MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxEDAOBgNVBAMT +B1Rlc3QxMjMwHhcNMTMwNDEwMTcyMzUyWhcNMTMwNTEwMTcyMzUyWjBvMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g +VmlldzEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRAwDgYDVQQD +EwdUZXN0MTIzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAu8WwMN9x +4Mz7YgkG2qy9g8/kl5ZoYrUM0ApHhaITAcL7RXLZaNipCf0w/YjYTQgj+75MK30x +TsnPeWNOEwA62gkHrZyyWfxBRO6kBYuIuI4roGDBJOmKQ1OEaDeIRKu7q5V8v3Cs +0wQDAQWTbhpxBZr9UYFgJUg8XWBfPrGJLVwsoiy4xrMhoTlNZKHfwOMMqVtSHkZX +qydYrcIzyjh+TO0e/xSNQ8MMRRbtqWgCHN6Rzhog3IHZu0RaPoukariopjXM/s0V +gTm3rHDHCOpna2pNblyiFlvbkoCs769mtNmx/yrDShO30jg/xaG8RypKDvTChzOT +oWW/XQ5VEXjbHwIDAQABo4HUMIHRMB0GA1UdDgQWBBRlT2dEZJY1tmUM8mZ0xnhS +GdD9TTCBoQYDVR0jBIGZMIGWgBRlT2dEZJY1tmUM8mZ0xnhSGdD9TaFzpHEwbzEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50 +YWluIFZpZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEQMA4G +A1UEAxMHVGVzdDEyM4IJAKhkCO1dDYMaMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN +AQELBQADggEBAKWWQ9S0V9wWjrMJe8exj1gklwD1Ysi0vi+h2tfixahelrpsNkWi +EFjoUSHEkW9ThLmtui646uAlwSiWtSn1XkGGmIJ3s+gmAFUcMc0CaK0dgoq/M9zn +fQ0Vkzc1tK4MLsf+CbPDywPycb6+T3dBkerbWn9GUpjGl1ANWlciXZZ3657m61sL +HhwUOBxbZZ6sYP4ed2SVCf45GgMyJ0VoUg5yI2JzPAgOkGfeEIPVXE1M94edJY4G +8eHYvXovJZwXvKFI+ZyS0KBPx8cpfw89RB9qmkxqNBIm8qWb3qBiuBEIPj+NF/7w +sC/Fv8NNXkVquy0xa0qdyJBABzWE18zGcXs= +-----END CERTIFICATE----- diff --git a/testdata/testkey.pk8 b/testdata/testkey.pk8 new file mode 100644 index 000000000..586c1bd5c Binary files /dev/null and b/testdata/testkey.pk8 differ diff --git a/testdata/testkey.x509.pem b/testdata/testkey.x509.pem new file mode 100644 index 000000000..e242d83e2 --- /dev/null +++ b/testdata/testkey.x509.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBBQUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g +VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE +AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0wODAyMjkwMTMzNDZaFw0zNTA3MTcwMTMzNDZaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G +A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI +hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM +qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4 +wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy +4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU +RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s +zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw +HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ +AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE +CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH +QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG +CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud +EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAHqvlozrUMRBBVEY0NqrrwFbinZa +J6cVosK0TyIUFf/azgMJWr+kLfcHCHJsIGnlw27drgQAvilFLAhLwn62oX6snb4Y +LCBOsVMR9FXYJLZW2+TcIkCRLXWG/oiVHQGo/rWuWkJgU134NDEFJCJGjDbiLCpe ++ZTWHdcwauTJ9pUbo8EvHRkU3cYfGmLaLfgn9gP+pWA7LFQNvXwBnDa6sppCccEX +31I828XzgXpJ4O+mDL1/dBd+ek8ZPUP0IgdyZm5MTYPhvVqGCHzzTy3sIeJFymwr +sBbmg2OAUNLEMO6nwmocSdN2ClirfxqCzJOLSDE4QyS9BAH6EhY6UFcOaE0= +-----END CERTIFICATE----- diff --git a/testdata/testkey_sha256.x509.pem b/testdata/testkey_sha256.x509.pem new file mode 100644 index 000000000..002ce8968 --- /dev/null +++ b/testdata/testkey_sha256.x509.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEqDCCA5CgAwIBAgIJAJNurL4H8gHfMA0GCSqGSIb3DQEBCwUAMIGUMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4g +VmlldzEQMA4GA1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UE +AxMHQW5kcm9pZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTAe +Fw0xMzA0MTAxODA1MzZaFw0xMzA1MTAxODA1MzZaMIGUMQswCQYDVQQGEwJVUzET +MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4G +A1UEChMHQW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9p +ZDEiMCAGCSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbTCCASAwDQYJKoZI +hvcNAQEBBQADggENADCCAQgCggEBANaTGQTexgskse3HYuDZ2CU+Ps1s6x3i/waM +qOi8qM1r03hupwqnbOYOuw+ZNVn/2T53qUPn6D1LZLjk/qLT5lbx4meoG7+yMLV4 +wgRDvkxyGLhG9SEVhvA4oU6Jwr44f46+z4/Kw9oe4zDJ6pPQp8PcSvNQIg1QCAcy +4ICXF+5qBTNZ5qaU7Cyz8oSgpGbIepTYOzEJOmc3Li9kEsBubULxWBjf/gOBzAzU +RNps3cO4JFgZSAGzJWQTT7/emMkod0jb9WdqVA2BVMi7yge54kdVMxHEa5r3b97s +zI5p58ii0I54JiCUP5lyfTwE/nKZHZnfm644oLIXf6MdW2r+6R8CAQOjgfwwgfkw +HQYDVR0OBBYEFEhZAFY9JyxGrhGGBaR0GawJyowRMIHJBgNVHSMEgcEwgb6AFEhZ +AFY9JyxGrhGGBaR0GawJyowRoYGapIGXMIGUMQswCQYDVQQGEwJVUzETMBEGA1UE +CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEQMA4GA1UEChMH +QW5kcm9pZDEQMA4GA1UECxMHQW5kcm9pZDEQMA4GA1UEAxMHQW5kcm9pZDEiMCAG +CSqGSIb3DQEJARYTYW5kcm9pZEBhbmRyb2lkLmNvbYIJAJNurL4H8gHfMAwGA1Ud +EwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAKRVj9hOaozH1W8Wb4CNj7sCWixh +UMMZJXkxUtvUVHZGefp6MdtYiD/ZM7YRwZphm9aNhkykbHJdZ3lPzeL2csCa+sDQ +8sIzGu0/aD6p4zgIKQZmz0mZHqPGbHoLWOmA9EexRCFZ7vO/kO56ZbyhfFz2DI3S +Yez65CabErOFhNX6WukSPbV3zfsHRDD5JUStb/ko6t99HXsvIO0Ax9poj60PpCC1 +SiFzHZUY9mOnUfJFs+3NWCwKtP9nho3mZ3pJ1i+SeF6JiqbE3KHl4CDBeVGcu3CK +fiUZ8e8iXVN471Cgc5GD6Ud1pS7ifNZJsKhbETQ63KmvHCLRPi4NmP67uDE= +-----END CERTIFICATE----- diff --git a/updater/install.c b/updater/install.c index 19054236c..1fc4fd394 100644 --- a/updater/install.c +++ b/updater/install.c @@ -1057,7 +1057,7 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { return StringValue(strdup("")); } uint8_t digest[SHA_DIGEST_SIZE]; - SHA(args[0]->data, args[0]->size, digest); + SHA_hash(args[0]->data, args[0]->size, digest); FreeValue(args[0]); if (argc == 1) { diff --git a/verifier.cpp b/verifier.cpp index 5f4c981e5..782a83863 100644 --- a/verifier.cpp +++ b/verifier.cpp @@ -20,6 +20,7 @@ #include "mincrypt/rsa.h" #include "mincrypt/sha.h" +#include "mincrypt/sha256.h" #include #include @@ -34,7 +35,7 @@ extern RecoveryUI* ui; // Return VERIFY_SUCCESS, VERIFY_FAILURE (if any error is encountered // or no key matches the signature). -int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys) { +int verify_file(const char* path, const Certificate* pKeys, unsigned int numKeys) { ui->SetProgress(0.0); FILE* f = fopen(path, "rb"); @@ -68,6 +69,7 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey } if (footer[2] != 0xff || footer[3] != 0xff) { + LOGE("footer is wrong\n"); fclose(f); return VERIFY_FAILURE; } @@ -139,8 +141,19 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey #define BUFFER_SIZE 4096 - SHA_CTX ctx; - SHA_init(&ctx); + bool need_sha1 = false; + bool need_sha256 = false; + for (i = 0; i < numKeys; ++i) { + switch (pKeys[i].hash_len) { + case SHA_DIGEST_SIZE: need_sha1 = true; break; + case SHA256_DIGEST_SIZE: need_sha256 = true; break; + } + } + + SHA_CTX sha1_ctx; + SHA256_CTX sha256_ctx; + SHA_init(&sha1_ctx); + SHA256_init(&sha256_ctx); unsigned char* buffer = (unsigned char*)malloc(BUFFER_SIZE); if (buffer == NULL) { LOGE("failed to alloc memory for sha1 buffer\n"); @@ -159,7 +172,8 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey fclose(f); return VERIFY_FAILURE; } - SHA_update(&ctx, buffer, size); + if (need_sha1) SHA_update(&sha1_ctx, buffer, size); + if (need_sha256) SHA256_update(&sha256_ctx, buffer, size); so_far += size; double f = so_far / (double)signed_len; if (f > frac + 0.02 || size == so_far) { @@ -170,12 +184,21 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey fclose(f); free(buffer); - const uint8_t* sha1 = SHA_final(&ctx); + const uint8_t* sha1 = SHA_final(&sha1_ctx); + const uint8_t* sha256 = SHA256_final(&sha256_ctx); + for (i = 0; i < numKeys; ++i) { + const uint8_t* hash; + switch (pKeys[i].hash_len) { + case SHA_DIGEST_SIZE: hash = sha1; break; + case SHA256_DIGEST_SIZE: hash = sha256; break; + default: continue; + } + // The 6 bytes is the "(signature_start) $ff $ff (comment_size)" that // the signing tool appends after the signature itself. - if (RSA_verify(pKeys+i, eocd + eocd_size - 6 - RSANUMBYTES, - RSANUMBYTES, sha1)) { + if (RSA_verify(pKeys[i].public_key, eocd + eocd_size - 6 - RSANUMBYTES, + RSANUMBYTES, hash, pKeys[i].hash_len)) { LOGI("whole-file signature verified against key %d\n", i); free(eocd); return VERIFY_SUCCESS; @@ -207,10 +230,19 @@ int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKey // The file may contain multiple keys in this format, separated by // commas. The last key must not be followed by a comma. // +// A Certificate is a pair of an RSAPublicKey and a particular hash +// (we support SHA-1 and SHA-256; we store the hash length to signify +// which is being used). The hash used is implied by the version number. +// +// 1: 2048-bit RSA key with e=3 and SHA-1 hash +// 2: 2048-bit RSA key with e=65537 and SHA-1 hash +// 3: 2048-bit RSA key with e=3 and SHA-256 hash +// 4: 2048-bit RSA key with e=65537 and SHA-256 hash +// // Returns NULL if the file failed to parse, or if it contain zero keys. -RSAPublicKey* +Certificate* load_keys(const char* filename, int* numKeys) { - RSAPublicKey* out = NULL; + Certificate* out = NULL; *numKeys = 0; FILE* f = fopen(filename, "r"); @@ -224,24 +256,38 @@ load_keys(const char* filename, int* numKeys) { bool done = false; while (!done) { ++*numKeys; - out = (RSAPublicKey*)realloc(out, *numKeys * sizeof(RSAPublicKey)); - RSAPublicKey* key = out + (*numKeys - 1); + out = (Certificate*)realloc(out, *numKeys * sizeof(Certificate)); + Certificate* cert = out + (*numKeys - 1); + cert->public_key = (RSAPublicKey*)malloc(sizeof(RSAPublicKey)); char start_char; if (fscanf(f, " %c", &start_char) != 1) goto exit; if (start_char == '{') { // a version 1 key has no version specifier. - key->exponent = 3; + cert->public_key->exponent = 3; + cert->hash_len = SHA_DIGEST_SIZE; } else if (start_char == 'v') { int version; if (fscanf(f, "%d {", &version) != 1) goto exit; - if (version == 2) { - key->exponent = 65537; - } else { - goto exit; + switch (version) { + case 2: + cert->public_key->exponent = 65537; + cert->hash_len = SHA_DIGEST_SIZE; + break; + case 3: + cert->public_key->exponent = 3; + cert->hash_len = SHA256_DIGEST_SIZE; + break; + case 4: + cert->public_key->exponent = 65537; + cert->hash_len = SHA256_DIGEST_SIZE; + break; + default: + goto exit; } } + RSAPublicKey* key = cert->public_key; if (fscanf(f, " %i , 0x%x , { %u", &(key->len), &(key->n0inv), &(key->n[0])) != 3) { goto exit; @@ -274,7 +320,7 @@ load_keys(const char* filename, int* numKeys) { goto exit; } - LOGI("read key e=%d\n", key->exponent); + LOGI("read key e=%d hash=%d\n", key->exponent, cert->hash_len); } } diff --git a/verifier.h b/verifier.h index e9ef3b722..6ce1b44d1 100644 --- a/verifier.h +++ b/verifier.h @@ -19,12 +19,17 @@ #include "mincrypt/rsa.h" +typedef struct Certificate { + int hash_len; // SHA_DIGEST_SIZE (SHA-1) or SHA256_DIGEST_SIZE (SHA-256) + RSAPublicKey* public_key; +} Certificate; + /* Look in the file for a signature footer, and verify that it * matches one of the given keys. Return one of the constants below. */ -int verify_file(const char* path, const RSAPublicKey *pKeys, unsigned int numKeys); +int verify_file(const char* path, const Certificate *pKeys, unsigned int numKeys); -RSAPublicKey* load_keys(const char* filename, int* numKeys); +Certificate* load_keys(const char* filename, int* numKeys); #define VERIFY_SUCCESS 0 #define VERIFY_FAILURE 1 diff --git a/verifier_test.cpp b/verifier_test.cpp index 79c55783d..7fab54748 100644 --- a/verifier_test.cpp +++ b/verifier_test.cpp @@ -20,80 +20,82 @@ #include "verifier.h" #include "ui.h" +#include "mincrypt/sha.h" +#include "mincrypt/sha256.h" // This is build/target/product/security/testkey.x509.pem after being // dumped out by dumpkey.jar. RSAPublicKey test_key = { 64, 0xc926ad21, - { 1795090719, 2141396315, 950055447, -1713398866, - -26044131, 1920809988, 546586521, -795969498, - 1776797858, -554906482, 1805317999, 1429410244, - 129622599, 1422441418, 1783893377, 1222374759, - -1731647369, 323993566, 28517732, 609753416, - 1826472888, 215237850, -33324596, -245884705, - -1066504894, 774857746, 154822455, -1797768399, - -1536767878, -1275951968, -1500189652, 87251430, - -1760039318, 120774784, 571297800, -599067824, - -1815042109, -483341846, -893134306, -1900097649, - -1027721089, 950095497, 555058928, 414729973, - 1136544882, -1250377212, 465547824, -236820568, - -1563171242, 1689838846, -404210357, 1048029507, - 895090649, 247140249, 178744550, -747082073, - -1129788053, 109881576, -350362881, 1044303212, - -522594267, -1309816990, -557446364, -695002876}, - { -857949815, -510492167, -1494742324, -1208744608, - 251333580, 2131931323, 512774938, 325948880, - -1637480859, 2102694287, -474399070, 792812816, - 1026422502, 2053275343, -1494078096, -1181380486, - 165549746, -21447327, -229719404, 1902789247, - 772932719, -353118870, -642223187, 216871947, - -1130566647, 1942378755, -298201445, 1055777370, - 964047799, 629391717, -2062222979, -384408304, - 191868569, -1536083459, -612150544, -1297252564, - -1592438046, -724266841, -518093464, -370899750, - -739277751, -1536141862, 1323144535, 61311905, - 1997411085, 376844204, 213777604, -217643712, - 9135381, 1625809335, -1490225159, -1342673351, - 1117190829, -57654514, 1825108855, -1281819325, - 1111251351, -1726129724, 1684324211, -1773988491, - 367251975, 810756730, -1941182952, 1175080310 }, + { 0x6afee91fu, 0x7fa31d5bu, 0x38a0b217u, 0x99df9baeu, + 0xfe72991du, 0x727d3c04u, 0x20943f99u, 0xd08e7826u, + 0x69e7c8a2u, 0xdeeccc8eu, 0x6b9af76fu, 0x553311c4u, + 0x07b9e247u, 0x54c8bbcau, 0x6a540d81u, 0x48dbf567u, + 0x98c92877u, 0x134fbfdeu, 0x01b32564u, 0x24581948u, + 0x6cddc3b8u, 0x0cd444dau, 0xfe0381ccu, 0xf15818dfu, + 0xc06e6d42u, 0x2e2f6412u, 0x093a6737u, 0x94d83b31u, + 0xa466c87au, 0xb3f284a0u, 0xa694ec2cu, 0x053359e6u, + 0x9717ee6au, 0x0732e080u, 0x220d5008u, 0xdc4af350u, + 0x93d0a7c3u, 0xe330c9eau, 0xcac3da1eu, 0x8ebecf8fu, + 0xc2be387fu, 0x38a14e89u, 0x211586f0u, 0x18b846f5u, + 0x43be4c72u, 0xb578c204u, 0x1bbfb230u, 0xf1e267a8u, + 0xa2d3e656u, 0x64b8e4feu, 0xe7e83d4bu, 0x3e77a943u, + 0x3559ffd9u, 0x0ebb0f99u, 0x0aa76ce6u, 0xd3786ea7u, + 0xbca8cd6bu, 0x068ca8e8u, 0xeb1de2ffu, 0x3e3ecd6cu, + 0xe0d9d825u, 0xb1edc762u, 0xdec60b24u, 0xd6931904u}, + { 0xccdcb989u, 0xe19281f9u, 0xa6e80accu, 0xb7f40560u, + 0x0efb0bccu, 0x7f12b0bbu, 0x1e90531au, 0x136d95d0u, + 0x9e660665u, 0x7d54918fu, 0xe3b93ea2u, 0x2f415d10u, + 0x3d2df6e6u, 0x7a627ecfu, 0xa6f22d70u, 0xb995907au, + 0x09de16b2u, 0xfeb8bd61u, 0xf24ec294u, 0x716a427fu, + 0x2e12046fu, 0xeaf3d56au, 0xd9b873adu, 0x0ced340bu, + 0xbc9cec09u, 0x73c65903u, 0xee39ce9bu, 0x3eede25au, + 0x397633b7u, 0x2583c165u, 0x8514f97du, 0xe9166510u, + 0x0b6fae99u, 0xa47139fdu, 0xdb8352f0u, 0xb2ad7f2cu, + 0xa11552e2u, 0xd4d490a7u, 0xe11e8568u, 0xe9e484dau, + 0xd3ef8449u, 0xa47055dau, 0x4edd9557u, 0x03a78ba1u, + 0x770e130du, 0x16762facu, 0x0cbdfcc4u, 0xf3070540u, + 0x008b6515u, 0x60e7e1b7u, 0xa72cf7f9u, 0xaff86e39u, + 0x4296faadu, 0xfc90430eu, 0x6cc8f377u, 0xb398fd43u, + 0x423c5997u, 0x991d59c4u, 0x6464bf73u, 0x96431575u, + 0x15e3d207u, 0x30532a7au, 0x8c4be618u, 0x460a4d76u }, 3 }; RSAPublicKey test_f4_key = { 64, 0xc9bd1f21, - { 293133087u, 3210546773u, 865313125u, 250921607u, - 3158780490u, 943703457u, 1242806226u, 2986289859u, - 2942743769u, 2457906415u, 2719374299u, 1783459420u, - 149579627u, 3081531591u, 3440738617u, 2788543742u, - 2758457512u, 1146764939u, 3699497403u, 2446203424u, - 1744968926u, 1159130537u, 2370028300u, 3978231572u, - 3392699980u, 1487782451u, 1180150567u, 2841334302u, - 3753960204u, 961373345u, 3333628321u, 748825784u, - 2978557276u, 1566596926u, 1613056060u, 2600292737u, - 1847226629u, 50398611u, 1890374404u, 2878700735u, - 2286201787u, 1401186359u, 619285059u, 731930817u, - 2340993166u, 1156490245u, 2992241729u, 151498140u, - 318782170u, 3480838990u, 2100383433u, 4223552555u, - 3628927011u, 4247846280u, 1759029513u, 4215632601u, - 2719154626u, 3490334597u, 1751299340u, 3487864726u, - 3668753795u, 4217506054u, 3748782284u, 3150295088u }, - { 1772626313u, 445326068u, 3477676155u, 1758201194u, - 2986784722u, 491035581u, 3922936562u, 702212696u, - 2979856666u, 3324974564u, 2488428922u, 3056318590u, - 1626954946u, 664714029u, 398585816u, 3964097931u, - 3356701905u, 2298377729u, 2040082097u, 3025491477u, - 539143308u, 3348777868u, 2995302452u, 3602465520u, - 212480763u, 2691021393u, 1307177300u, 704008044u, - 2031136606u, 1054106474u, 3838318865u, 2441343869u, - 1477566916u, 700949900u, 2534790355u, 3353533667u, - 336163563u, 4106790558u, 2701448228u, 1571536379u, - 1103842411u, 3623110423u, 1635278839u, 1577828979u, - 910322800u, 715583630u, 138128831u, 1017877531u, - 2289162787u, 447994798u, 1897243165u, 4121561445u, - 4150719842u, 2131821093u, 2262395396u, 3305771534u, - 980753571u, 3256525190u, 3128121808u, 1072869975u, - 3507939515u, 4229109952u, 118381341u, 2209831334u }, + { 0x1178db1fu, 0xbf5d0e55u, 0x3393a165u, 0x0ef4c287u, + 0xbc472a4au, 0x383fc5a1u, 0x4a13b7d2u, 0xb1ff2ac3u, + 0xaf66b4d9u, 0x9280acefu, 0xa2165bdbu, 0x6a4d6e5cu, + 0x08ea676bu, 0xb7ac70c7u, 0xcd158139u, 0xa635ccfeu, + 0xa46ab8a8u, 0x445a3e8bu, 0xdc81d9bbu, 0x91ce1a20u, + 0x68021cdeu, 0x4516eda9u, 0x8d43c30cu, 0xed1eff14u, + 0xca387e4cu, 0x58adc233u, 0x4657ab27u, 0xa95b521eu, + 0xdfc0e30cu, 0x394d64a1u, 0xc6b321a1u, 0x2ca22cb8u, + 0xb1892d5cu, 0x5d605f3eu, 0x6025483cu, 0x9afd5181u, + 0x6e1a7105u, 0x03010593u, 0x70acd304u, 0xab957cbfu, + 0x8844abbbu, 0x53846837u, 0x24e98a43u, 0x2ba060c1u, + 0x8b88b88eu, 0x44eea405u, 0xb259fc41u, 0x0907ad9cu, + 0x13003adau, 0xcf79634eu, 0x7d314ec9u, 0xfbbe4c2bu, + 0xd84d0823u, 0xfd30fd88u, 0x68d8a909u, 0xfb4572d9u, + 0xa21301c2u, 0xd00a4785u, 0x6862b50cu, 0xcfe49796u, + 0xdaacbd83u, 0xfb620906u, 0xdf71e0ccu, 0xbbc5b030u }, + { 0x69a82189u, 0x1a8b22f4u, 0xcf49207bu, 0x68cc056au, + 0xb206b7d2u, 0x1d449bbdu, 0xe9d342f2u, 0x29daea58u, + 0xb19d011au, 0xc62f15e4u, 0x9452697au, 0xb62bb87eu, + 0x60f95cc2u, 0x279ebb2du, 0x17c1efd8u, 0xec47558bu, + 0xc81334d1u, 0x88fe7601u, 0x79992eb1u, 0xb4555615u, + 0x2022ac8cu, 0xc79a4b8cu, 0xb288b034u, 0xd6b942f0u, + 0x0caa32fbu, 0xa065ba51u, 0x4de9f154u, 0x29f64f6cu, + 0x7910af5eu, 0x3ed4636au, 0xe4c81911u, 0x9183f37du, + 0x5811e1c4u, 0x29c7a58cu, 0x9715d4d3u, 0xc7e2dce3u, + 0x140972ebu, 0xf4c8a69eu, 0xa104d424u, 0x5dabbdfbu, + 0x41cb4c6bu, 0xd7f44717u, 0x61785ff7u, 0x5e0bc273u, + 0x36426c70u, 0x2aa6f08eu, 0x083badbfu, 0x3cab941bu, + 0x8871da23u, 0x1ab3dbaeu, 0x7115a21du, 0xf5aa0965u, + 0xf766f562u, 0x7f110225u, 0x86d96a04u, 0xc50a120eu, + 0x3a751ca3u, 0xc21aa186u, 0xba7359d0u, 0x3ff2b257u, + 0xd116e8bbu, 0xfc1318c0u, 0x070e5b1du, 0x83b759a6u }, 65537 }; @@ -130,30 +132,37 @@ class FakeUI : public RecoveryUI { int main(int argc, char **argv) { if (argc < 2 || argc > 4) { - fprintf(stderr, "Usage: %s [-f4 | -file ] \n", argv[0]); + fprintf(stderr, "Usage: %s [-sha256] [-f4 | -file ] \n", argv[0]); return 2; } - RSAPublicKey* key = &test_key; + Certificate default_cert; + Certificate* cert = &default_cert; + cert->public_key = &test_key; + cert->hash_len = SHA_DIGEST_SIZE; int num_keys = 1; ++argv; + if (strcmp(argv[0], "-sha256") == 0) { + ++argv; + cert->hash_len = SHA256_DIGEST_SIZE; + } if (strcmp(argv[0], "-f4") == 0) { ++argv; - key = &test_f4_key; + cert->public_key = &test_f4_key; } else if (strcmp(argv[0], "-file") == 0) { ++argv; - key = load_keys(argv[0], &num_keys); + cert = load_keys(argv[0], &num_keys); ++argv; } ui = new FakeUI(); - int result = verify_file(*argv, key, num_keys); + int result = verify_file(*argv, cert, num_keys); if (result == VERIFY_SUCCESS) { - printf("SUCCESS\n"); + printf("VERIFIED\n"); return 0; } else if (result == VERIFY_FAILURE) { - printf("FAILURE\n"); + printf("NOT VERIFIED\n"); return 1; } else { printf("bad return value\n"); diff --git a/verifier_test.sh b/verifier_test.sh index 378b0e5ff..65f77f401 100755 --- a/verifier_test.sh +++ b/verifier_test.sh @@ -64,33 +64,39 @@ $ADB push $ANDROID_PRODUCT_OUT/system/bin/verifier_test \ expect_succeed() { testname "$1 (should succeed)" $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip - run_command $WORK_DIR/verifier_test $WORK_DIR/package.zip || fail + shift + run_command $WORK_DIR/verifier_test "$@" $WORK_DIR/package.zip || fail } expect_fail() { testname "$1 (should fail)" $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip - run_command $WORK_DIR/verifier_test $WORK_DIR/package.zip && fail -} - -expect_succeed_f4() { - testname "$1 (should succeed)" - $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip - run_command $WORK_DIR/verifier_test -f4 $WORK_DIR/package.zip || fail -} - -expect_fail_f4() { - testname "$1 (should fail)" - $ADB push $DATA_DIR/$1 $WORK_DIR/package.zip - run_command $WORK_DIR/verifier_test -f4 $WORK_DIR/package.zip && fail + shift + run_command $WORK_DIR/verifier_test "$@" $WORK_DIR/package.zip && fail } +# not signed at all expect_fail unsigned.zip +# signed in the pre-donut way expect_fail jarsigned.zip + +# success cases expect_succeed otasigned.zip -expect_fail_f4 otasigned.zip -expect_succeed_f4 otasigned_f4.zip +expect_succeed otasigned_f4.zip -f4 +expect_succeed otasigned_sha256.zip -sha256 +expect_succeed otasigned_f4_sha256.zip -sha256 -f4 + +# verified against different key +expect_fail otasigned.zip -f4 expect_fail otasigned_f4.zip + +# verified against right key but wrong hash algorithm +expect_fail otasigned.zip -sha256 +expect_fail otasigned_f4.zip -sha256 -f4 +expect_fail otasigned_sha256.zip +expect_fail otasigned_f4_sha256.zip -f4 + +# various other cases expect_fail random.zip expect_fail fake-eocd.zip expect_fail alter-metadata.zip -- cgit v1.2.3 From 596b342a0476629badb41b840494254a19c57dae Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 14 May 2013 11:03:02 -0700 Subject: recovery: turn on text display for install errors in debug builds Hopefully this will reduce the number of OTA "bugs" reported that are really just someone having changed their system partition, invalidating future incremental OTAs. Also fixes a longstanding TODO about putting LOGE() output in the on-screen display. Change-Id: I44e5be65b2dee7ebce2cce28ccd920dc3d6e522e --- common.h | 6 ++++-- recovery.cpp | 35 +++++++++++++++++++++++++++++++++-- verifier_test.cpp | 14 ++++++++++---- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/common.h b/common.h index 3587a31f2..768f499f9 100644 --- a/common.h +++ b/common.h @@ -18,13 +18,13 @@ #define RECOVERY_COMMON_H #include +#include #ifdef __cplusplus extern "C" { #endif -// TODO: restore ui_print for LOGE -#define LOGE(...) fprintf(stdout, "E:" __VA_ARGS__) +#define LOGE(...) ui_print("E:" __VA_ARGS__) #define LOGW(...) fprintf(stdout, "W:" __VA_ARGS__) #define LOGI(...) fprintf(stdout, "I:" __VA_ARGS__) @@ -44,6 +44,8 @@ typedef struct fstab_rec Volume; // fopen a file, mounting volumes and making parent dirs as necessary. FILE* fopen_path(const char *path, const char *mode); +void ui_print(const char* format, ...); + #ifdef __cplusplus } #endif diff --git a/recovery.cpp b/recovery.cpp index 7002cb8a4..a84d8333a 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -15,11 +15,13 @@ */ #include +#include #include #include #include #include #include +#include #include #include #include @@ -27,7 +29,6 @@ #include #include #include -#include #include "bootloader.h" #include "common.h" @@ -801,6 +802,24 @@ load_locale_from_cache() { } } +static RecoveryUI* gCurrentUI = NULL; + +void +ui_print(const char* format, ...) { + char buffer[256]; + + va_list ap; + va_start(ap, format); + vsnprintf(buffer, sizeof(buffer), format, ap); + va_end(ap); + + if (gCurrentUI != NULL) { + gCurrentUI->Print("%s", buffer); + } else { + fputs(buffer, stdout); + } +} + int main(int argc, char **argv) { time_t start = time(NULL); @@ -856,6 +875,7 @@ main(int argc, char **argv) { Device* device = make_device(); ui = device->GetUI(); + gCurrentUI = ui; ui->Init(); ui->SetLocale(locale); @@ -909,7 +929,18 @@ main(int argc, char **argv) { LOGE("Cache wipe (requested by package) failed."); } } - if (status != INSTALL_SUCCESS) ui->Print("Installation aborted.\n"); + if (status != INSTALL_SUCCESS) { + ui->Print("Installation aborted.\n"); + + // If this is an eng or userdebug build, then automatically + // turn the text display on if the script fails so the error + // message is visible. + char buffer[PROPERTY_VALUE_MAX+1]; + property_get("ro.build.fingerprint", buffer, ""); + if (strstr(buffer, ":userdebug/") || strstr(buffer, ":eng/")) { + ui->ShowText(true); + } + } } else if (wipe_data) { if (device->WipeData()) status = INSTALL_ERROR; if (erase_volume("/data")) status = INSTALL_ERROR; diff --git a/verifier_test.cpp b/verifier_test.cpp index 7fab54748..1063cbae5 100644 --- a/verifier_test.cpp +++ b/verifier_test.cpp @@ -18,6 +18,7 @@ #include #include +#include "common.h" #include "verifier.h" #include "ui.h" #include "mincrypt/sha.h" @@ -115,13 +116,10 @@ class FakeUI : public RecoveryUI { bool IsTextVisible() { return false; } bool WasTextEverVisible() { return false; } void Print(const char* fmt, ...) { - char buf[256]; va_list ap; va_start(ap, fmt); - vsnprintf(buf, 256, fmt, ap); + vfprintf(stderr, fmt, ap); va_end(ap); - - fputs(buf, stderr); } void StartMenu(const char* const * headers, const char* const * items, @@ -130,6 +128,14 @@ class FakeUI : public RecoveryUI { void EndMenu() { } }; +void +ui_print(const char* format, ...) { + va_list ap; + va_start(ap, format); + vfprintf(stdout, format, ap); + va_end(ap); +} + int main(int argc, char **argv) { if (argc < 2 || argc > 4) { fprintf(stderr, "Usage: %s [-sha256] [-f4 | -file ] \n", argv[0]); -- cgit v1.2.3 From 46bee63afcd1e2817cdc75a6a8cefdcfdc3e8429 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Thu, 16 May 2013 11:23:48 -0700 Subject: recovery: save logs from the last few invocations of recovery Extends the last_log mechanism to save logs from the last six invocations of recovery, so that we're more likely to have useful logs even if the device has repeatedly booted into recovery. Change-Id: I08ae7a09553ada45f9e0733fe1e55e5a22efd9f9 --- recovery.cpp | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/recovery.cpp b/recovery.cpp index a84d8333a..840e63c42 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -59,10 +59,11 @@ static const struct option OPTIONS[] = { { NULL, 0, NULL, 0 }, }; +#define LAST_LOG_FILE "/cache/recovery/last_log" + static const char *COMMAND_FILE = "/cache/recovery/command"; static const char *INTENT_FILE = "/cache/recovery/intent"; static const char *LOG_FILE = "/cache/recovery/log"; -static const char *LAST_LOG_FILE = "/cache/recovery/last_log"; static const char *LAST_INSTALL_FILE = "/cache/recovery/last_install"; static const char *LOCALE_FILE = "/cache/recovery/last_locale"; static const char *CACHE_ROOT = "/cache"; @@ -260,6 +261,21 @@ copy_log_file(const char* source, const char* destination, int append) { } } +// Rename last_log -> last_log.1 -> last_log.2 -> ... -> last_log.$max +// Overwrites any existing last_log.$max. +static void +rotate_last_logs(int max) { + char oldfn[256]; + char newfn[256]; + + int i; + for (i = max-1; i >= 0; --i) { + snprintf(oldfn, sizeof(oldfn), (i==0) ? LAST_LOG_FILE : (LAST_LOG_FILE ".%d"), i); + snprintf(newfn, sizeof(newfn), LAST_LOG_FILE ".%d", i+1); + // ignore errors + rename(oldfn, newfn); + } +} // clear the recovery command and prepare to boot a (hopefully working) system, // copy our log file to cache as well (for the system to read), and @@ -843,6 +859,8 @@ main(int argc, char **argv) { printf("Starting recovery on %s", ctime(&start)); load_volume_table(); + ensure_path_mounted(LAST_LOG_FILE); + rotate_last_logs(5); get_args(&argc, &argv); int previous_runs = 0; -- cgit v1.2.3 From 2f2c98869b5391310965c7d154c68f4b28e0ccfb Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Tue, 4 Jun 2013 13:11:44 -0700 Subject: start healthd in recovery Change-Id: I16e3e0ddb8ca062431deb4be83c5be5eb786d76f --- etc/init.rc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/etc/init.rc b/etc/init.rc index abc7b318b..b26d2ae73 100644 --- a/etc/init.rc +++ b/etc/init.rc @@ -2,6 +2,7 @@ import /init.recovery.${ro.hardware}.rc on early-init start ueventd + start healthd on init export PATH /sbin @@ -40,6 +41,9 @@ on boot service ueventd /sbin/ueventd critical +service healthd /sbin/healthd -n + critical + service recovery /sbin/recovery service adbd /sbin/adbd recovery -- cgit v1.2.3 From f24fd7e8479d54eaa2b73db5a3a3ad076a13f72d Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 2 Jul 2013 11:43:25 -0700 Subject: recovery: copy logs to cache more aggressively Copy logs to /cache immediately upon a package installation failure; don't wait for recovery to finish. (If the user reboots without exiting recovery the "right" way, the logs never get copied at all.) Change-Id: Iee342944e7ded63da5a4af33d11ebc876f6c0835 --- recovery.cpp | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/recovery.cpp b/recovery.cpp index c82844d25..b7fb616ce 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -283,6 +283,19 @@ rotate_last_logs(int max) { } } +static void +copy_logs() { + // Copy logs to cache so the system can find out what happened. + copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); + copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false); + copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false); + chmod(LOG_FILE, 0600); + chown(LOG_FILE, 1000, 1000); // system user + chmod(LAST_LOG_FILE, 0640); + chmod(LAST_INSTALL_FILE, 0644); + sync(); +} + // clear the recovery command and prepare to boot a (hopefully working) system, // copy our log file to cache as well (for the system to read), and // record any intent we were asked to communicate back to the system. @@ -312,14 +325,7 @@ finish_recovery(const char *send_intent) { check_and_fclose(fp, LOCALE_FILE); } - // Copy logs to cache so the system can find out what happened. - copy_log_file(TEMPORARY_LOG_FILE, LOG_FILE, true); - copy_log_file(TEMPORARY_LOG_FILE, LAST_LOG_FILE, false); - copy_log_file(TEMPORARY_INSTALL_FILE, LAST_INSTALL_FILE, false); - chmod(LOG_FILE, 0600); - chown(LOG_FILE, 1000, 1000); // system user - chmod(LAST_LOG_FILE, 0640); - chmod(LAST_INSTALL_FILE, 0644); + copy_logs(); // Reset to normal system boot so recovery won't cycle indefinitely. struct bootloader_message boot; @@ -789,6 +795,7 @@ prompt_and_wait(Device* device, int status) { if (status != INSTALL_SUCCESS) { ui->SetBackground(RecoveryUI::ERROR); ui->Print("Installation aborted.\n"); + copy_logs(); } else if (!ui->IsTextVisible()) { return; // reboot if logs aren't visible } else { @@ -866,7 +873,7 @@ main(int argc, char **argv) { load_volume_table(); ensure_path_mounted(LAST_LOG_FILE); - rotate_last_logs(5); + rotate_last_logs(10); get_args(&argc, &argv); int previous_runs = 0; @@ -979,6 +986,7 @@ main(int argc, char **argv) { } if (status == INSTALL_ERROR || status == INSTALL_CORRUPT) { + copy_logs(); ui->SetBackground(RecoveryUI::ERROR); } if (status != INSTALL_SUCCESS || ui->IsTextVisible()) { -- cgit v1.2.3 From 5b468fc9305bf3adef681fa1e56364fc51761af8 Mon Sep 17 00:00:00 2001 From: yetta_wu Date: Tue, 25 Jun 2013 15:03:11 +0800 Subject: recovery: init backgroundIcon properly to avoid recovery mode crash We met factory issue that some devices would crash in recovery mode because the backgroundIcon array did not reset to NULL when initializing. Bug: 9568624 Change-Id: I13c7a7cc1053a7ffdbadd71740c1a2b4a2af6bba Signed-off-by: yetta_wu Signed-off-by: Iliyan Malchev --- screen_ui.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/screen_ui.cpp b/screen_ui.cpp index 222de00ee..93e260936 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -82,6 +82,10 @@ ScreenRecoveryUI::ScreenRecoveryUI() : install_overlay_offset_y(190), overlay_offset_x(-1), overlay_offset_y(-1) { + + for (int i = 0; i < 5; i++) + backgroundIcon[i] = NULL; + pthread_mutex_init(&updateMutex, NULL); self = this; } -- cgit v1.2.3 From fafc85b4ad7a5679c6b562bed64460732e05fd1e Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 9 Jul 2013 12:29:45 -0700 Subject: recovery: move log output to stdout Recovery currently has a random mix of messages printed to stdout and messages printed to stderr, which can make logs hard to read. Move everything to stdout. Change-Id: Ie33bd4a9e1272e731302569cdec918e0534c48a6 --- edify/expr.c | 4 +-- edify/main.c | 10 ++++---- install.cpp | 1 + minui/graphics.c | 4 +-- mtdutils/mtdutils.c | 26 +++++++++---------- recovery.cpp | 3 +-- updater/install.c | 72 ++++++++++++++++++++++++++--------------------------- updater/updater.c | 24 +++++++++--------- 8 files changed, 72 insertions(+), 72 deletions(-) diff --git a/edify/expr.c b/edify/expr.c index 07a8ceb6a..a2f1f99d7 100644 --- a/edify/expr.c +++ b/edify/expr.c @@ -287,13 +287,13 @@ Value* LessThanIntFn(const char* name, State* state, int argc, Expr* argv[]) { long l_int = strtol(left, &end, 10); if (left[0] == '\0' || *end != '\0') { - fprintf(stderr, "[%s] is not an int\n", left); + printf("[%s] is not an int\n", left); goto done; } long r_int = strtol(right, &end, 10); if (right[0] == '\0' || *end != '\0') { - fprintf(stderr, "[%s] is not an int\n", right); + printf("[%s] is not an int\n", right); goto done; } diff --git a/edify/main.c b/edify/main.c index 855704385..9e6bab7ca 100644 --- a/edify/main.c +++ b/edify/main.c @@ -34,8 +34,8 @@ int expect(const char* expr_str, const char* expected, int* errors) { int error_count = 0; error = yyparse(&e, &error_count); if (error > 0 || error_count > 0) { - fprintf(stderr, "error parsing \"%s\" (%d errors)\n", - expr_str, error_count); + printf("error parsing \"%s\" (%d errors)\n", + expr_str, error_count); ++*errors; return 0; } @@ -49,7 +49,7 @@ int expect(const char* expr_str, const char* expected, int* errors) { free(state.errmsg); free(state.script); if (result == NULL && expected != NULL) { - fprintf(stderr, "error evaluating \"%s\"\n", expr_str); + printf("error evaluating \"%s\"\n", expr_str); ++*errors; return 0; } @@ -59,8 +59,8 @@ int expect(const char* expr_str, const char* expected, int* errors) { } if (strcmp(result, expected) != 0) { - fprintf(stderr, "evaluating \"%s\": expected \"%s\", got \"%s\"\n", - expr_str, expected, result); + printf("evaluating \"%s\": expected \"%s\", got \"%s\"\n", + expr_str, expected, result); ++*errors; free(result); return 0; diff --git a/install.cpp b/install.cpp index 0cb5cc7df..e1ab848f6 100644 --- a/install.cpp +++ b/install.cpp @@ -154,6 +154,7 @@ try_update_binary(const char *path, ZipArchive *zip, int* wipe_cache) { } else { ui->Print("\n"); } + fflush(stdout); } else if (strcmp(command, "wipe_cache") == 0) { *wipe_cache = 1; } else if (strcmp(command, "clear_display") == 0) { diff --git a/minui/graphics.c b/minui/graphics.c index 4968eac7a..d75716531 100644 --- a/minui/graphics.c +++ b/minui/graphics.c @@ -385,8 +385,8 @@ int gr_init(void) get_memory_surface(&gr_mem_surface); - fprintf(stderr, "framebuffer: fd %d (%d x %d)\n", - gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height); + printf("framebuffer: fd %d (%d x %d)\n", + gr_fb_fd, gr_framebuffer[0].width, gr_framebuffer[0].height); /* start with 0 as front (displayed) and 1 as back (drawing) */ gr_active_fb = 0; diff --git a/mtdutils/mtdutils.c b/mtdutils/mtdutils.c index 107cbb9a8..d04b26efa 100644 --- a/mtdutils/mtdutils.c +++ b/mtdutils/mtdutils.c @@ -289,7 +289,7 @@ static int read_block(const MtdPartition *partition, int fd, char *data) { struct mtd_ecc_stats before, after; if (ioctl(fd, ECCGETSTATS, &before)) { - fprintf(stderr, "mtd: ECCGETSTATS error (%s)\n", strerror(errno)); + printf("mtd: ECCGETSTATS error (%s)\n", strerror(errno)); return -1; } @@ -300,13 +300,13 @@ static int read_block(const MtdPartition *partition, int fd, char *data) while (pos + size <= (int) partition->size) { if (lseek64(fd, pos, SEEK_SET) != pos || read(fd, data, size) != size) { - fprintf(stderr, "mtd: read error at 0x%08llx (%s)\n", + printf("mtd: read error at 0x%08llx (%s)\n", pos, strerror(errno)); } else if (ioctl(fd, ECCGETSTATS, &after)) { - fprintf(stderr, "mtd: ECCGETSTATS error (%s)\n", strerror(errno)); + printf("mtd: ECCGETSTATS error (%s)\n", strerror(errno)); return -1; } else if (after.failed != before.failed) { - fprintf(stderr, "mtd: ECC errors (%d soft, %d hard) at 0x%08llx\n", + printf("mtd: ECC errors (%d soft, %d hard) at 0x%08llx\n", after.corrected - before.corrected, after.failed - before.failed, pos); // copy the comparison baseline for the next read. @@ -431,39 +431,39 @@ static int write_block(MtdWriteContext *ctx, const char *data) int retry; for (retry = 0; retry < 2; ++retry) { if (ioctl(fd, MEMERASE, &erase_info) < 0) { - fprintf(stderr, "mtd: erase failure at 0x%08lx (%s)\n", + printf("mtd: erase failure at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (lseek(fd, pos, SEEK_SET) != pos || write(fd, data, size) != size) { - fprintf(stderr, "mtd: write error at 0x%08lx (%s)\n", + printf("mtd: write error at 0x%08lx (%s)\n", pos, strerror(errno)); } char verify[size]; if (lseek(fd, pos, SEEK_SET) != pos || read(fd, verify, size) != size) { - fprintf(stderr, "mtd: re-read error at 0x%08lx (%s)\n", + printf("mtd: re-read error at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (memcmp(data, verify, size) != 0) { - fprintf(stderr, "mtd: verification error at 0x%08lx (%s)\n", + printf("mtd: verification error at 0x%08lx (%s)\n", pos, strerror(errno)); continue; } if (retry > 0) { - fprintf(stderr, "mtd: wrote block after %d retries\n", retry); + printf("mtd: wrote block after %d retries\n", retry); } - fprintf(stderr, "mtd: successfully wrote block at %lx\n", pos); + printf("mtd: successfully wrote block at %lx\n", pos); return 0; // Success! } // Try to erase it once more as we give up on this block add_bad_block_offset(ctx, pos); - fprintf(stderr, "mtd: skipping write block at 0x%08lx\n", pos); + printf("mtd: skipping write block at 0x%08lx\n", pos); ioctl(fd, MEMERASE, &erase_info); pos += partition->erase_size; } @@ -526,7 +526,7 @@ off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks) while (blocks-- > 0) { loff_t bpos = pos; if (ioctl(ctx->fd, MEMGETBADBLOCK, &bpos) > 0) { - fprintf(stderr, "mtd: not erasing bad block at 0x%08lx\n", pos); + printf("mtd: not erasing bad block at 0x%08lx\n", pos); pos += ctx->partition->erase_size; continue; // Don't try to erase known factory-bad blocks. } @@ -535,7 +535,7 @@ off_t mtd_erase_blocks(MtdWriteContext *ctx, int blocks) erase_info.start = pos; erase_info.length = ctx->partition->erase_size; if (ioctl(ctx->fd, MEMERASE, &erase_info) < 0) { - fprintf(stderr, "mtd: erase failure at 0x%08lx\n", pos); + printf("mtd: erase failure at 0x%08lx\n", pos); } pos += ctx->partition->erase_size; } diff --git a/recovery.cpp b/recovery.cpp index b7fb616ce..d95339733 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -920,8 +920,7 @@ main(int argc, char **argv) { sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); if (!sehandle) { - fprintf(stderr, "Warning: No file_contexts\n"); - ui->Print("Warning: No file_contexts\n"); + ui->Print("Warning: No file_contexts\n"); } device->StartRecovery(); diff --git a/updater/install.c b/updater/install.c index 1fc4fd394..9fa06a225 100644 --- a/updater/install.c +++ b/updater/install.c @@ -97,13 +97,13 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { const MtdPartition* mtd; mtd = mtd_find_partition_by_name(location); if (mtd == NULL) { - fprintf(stderr, "%s: no mtd partition named \"%s\"", + printf("%s: no mtd partition named \"%s\"", name, location); result = strdup(""); goto done; } if (mtd_mount_partition(mtd, mount_point, fs_type, 0 /* rw */) != 0) { - fprintf(stderr, "mtd mount of %s failed: %s\n", + printf("mtd mount of %s failed: %s\n", location, strerror(errno)); result = strdup(""); goto done; @@ -112,7 +112,7 @@ Value* MountFn(const char* name, State* state, int argc, Expr* argv[]) { } else { if (mount(location, mount_point, fs_type, MS_NOATIME | MS_NODEV | MS_NODIRATIME, "") < 0) { - fprintf(stderr, "%s: failed to mount %s at %s: %s\n", + printf("%s: failed to mount %s at %s: %s\n", name, location, mount_point, strerror(errno)); result = strdup(""); } else { @@ -175,7 +175,7 @@ Value* UnmountFn(const char* name, State* state, int argc, Expr* argv[]) { scan_mounted_volumes(); const MountedVolume* vol = find_mounted_volume_by_mount_point(mount_point); if (vol == NULL) { - fprintf(stderr, "unmount of %s failed; no such volume\n", mount_point); + printf("unmount of %s failed; no such volume\n", mount_point); result = strdup(""); } else { unmount_mounted_volume(vol); @@ -233,25 +233,25 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { mtd_scan_partitions(); const MtdPartition* mtd = mtd_find_partition_by_name(location); if (mtd == NULL) { - fprintf(stderr, "%s: no mtd partition named \"%s\"", + printf("%s: no mtd partition named \"%s\"", name, location); result = strdup(""); goto done; } MtdWriteContext* ctx = mtd_write_partition(mtd); if (ctx == NULL) { - fprintf(stderr, "%s: can't write \"%s\"", name, location); + printf("%s: can't write \"%s\"", name, location); result = strdup(""); goto done; } if (mtd_erase_blocks(ctx, -1) == -1) { mtd_write_close(ctx); - fprintf(stderr, "%s: failed to erase \"%s\"", name, location); + printf("%s: failed to erase \"%s\"", name, location); result = strdup(""); goto done; } if (mtd_write_close(ctx) != 0) { - fprintf(stderr, "%s: failed to close \"%s\"", name, location); + printf("%s: failed to close \"%s\"", name, location); result = strdup(""); goto done; } @@ -260,7 +260,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { } else if (strcmp(fs_type, "ext4") == 0) { int status = make_ext4fs(location, atoll(fs_size), mount_point, sehandle); if (status != 0) { - fprintf(stderr, "%s: make_ext4fs failed (%d) on %s", + printf("%s: make_ext4fs failed (%d) on %s", name, status, location); result = strdup(""); goto done; @@ -268,7 +268,7 @@ Value* FormatFn(const char* name, State* state, int argc, Expr* argv[]) { result = location; #endif } else { - fprintf(stderr, "%s: unsupported fs_type \"%s\" partition_type \"%s\"", + printf("%s: unsupported fs_type \"%s\" partition_type \"%s\"", name, fs_type, partition_type); } @@ -394,13 +394,13 @@ Value* PackageExtractFileFn(const char* name, State* state, ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; const ZipEntry* entry = mzFindZipEntry(za, zip_path); if (entry == NULL) { - fprintf(stderr, "%s: no %s in package\n", name, zip_path); + printf("%s: no %s in package\n", name, zip_path); goto done2; } FILE* f = fopen(dest_path, "wb"); if (f == NULL) { - fprintf(stderr, "%s: can't open %s for write: %s\n", + printf("%s: can't open %s for write: %s\n", name, dest_path, strerror(errno)); goto done2; } @@ -426,14 +426,14 @@ Value* PackageExtractFileFn(const char* name, State* state, ZipArchive* za = ((UpdaterInfo*)(state->cookie))->package_zip; const ZipEntry* entry = mzFindZipEntry(za, zip_path); if (entry == NULL) { - fprintf(stderr, "%s: no %s in package\n", name, zip_path); + printf("%s: no %s in package\n", name, zip_path); goto done1; } v->size = mzGetZipEntryUncompLen(entry); v->data = malloc(v->size); if (v->data == NULL) { - fprintf(stderr, "%s: failed to allocate %ld bytes for %s\n", + printf("%s: failed to allocate %ld bytes for %s\n", name, (long)v->size, zip_path); goto done1; } @@ -460,13 +460,13 @@ static int make_parents(char* name) { *p = '\0'; if (make_parents(name) < 0) return -1; int result = mkdir(name, 0700); - if (result == 0) fprintf(stderr, "symlink(): created [%s]\n", name); + if (result == 0) printf("symlink(): created [%s]\n", name); *p = '/'; if (result == 0 || errno == EEXIST) { // successfully created or already existed; we're done return 0; } else { - fprintf(stderr, "failed to mkdir %s: %s\n", name, strerror(errno)); + printf("failed to mkdir %s: %s\n", name, strerror(errno)); return -1; } } @@ -494,18 +494,18 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { for (i = 0; i < argc-1; ++i) { if (unlink(srcs[i]) < 0) { if (errno != ENOENT) { - fprintf(stderr, "%s: failed to remove %s: %s\n", + printf("%s: failed to remove %s: %s\n", name, srcs[i], strerror(errno)); ++bad; } } if (make_parents(srcs[i])) { - fprintf(stderr, "%s: failed to symlink %s to %s: making parents failed\n", + printf("%s: failed to symlink %s to %s: making parents failed\n", name, srcs[i], target); ++bad; } if (symlink(target, srcs[i]) < 0) { - fprintf(stderr, "%s: failed to symlink %s to %s: %s\n", + printf("%s: failed to symlink %s to %s: %s\n", name, srcs[i], target, strerror(errno)); ++bad; } @@ -574,12 +574,12 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { for (i = 3; i < argc; ++i) { if (chown(args[i], uid, gid) < 0) { - fprintf(stderr, "%s: chown of %s to %d %d failed: %s\n", + printf("%s: chown of %s to %d %d failed: %s\n", name, args[i], uid, gid, strerror(errno)); ++bad; } if (chmod(args[i], mode) < 0) { - fprintf(stderr, "%s: chmod of %s to %o failed: %s\n", + printf("%s: chmod of %s to %o failed: %s\n", name, args[i], mode, strerror(errno)); ++bad; } @@ -720,7 +720,7 @@ static bool write_raw_image_cb(const unsigned char* data, int data_len, void* ctx) { int r = mtd_write_data((MtdWriteContext*)ctx, (const char *)data, data_len); if (r == data_len) return true; - fprintf(stderr, "%s\n", strerror(errno)); + printf("%s\n", strerror(errno)); return false; } @@ -752,14 +752,14 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { mtd_scan_partitions(); const MtdPartition* mtd = mtd_find_partition_by_name(partition); if (mtd == NULL) { - fprintf(stderr, "%s: no mtd partition named \"%s\"\n", name, partition); + printf("%s: no mtd partition named \"%s\"\n", name, partition); result = strdup(""); goto done; } MtdWriteContext* ctx = mtd_write_partition(mtd); if (ctx == NULL) { - fprintf(stderr, "%s: can't write mtd partition \"%s\"\n", + printf("%s: can't write mtd partition \"%s\"\n", name, partition); result = strdup(""); goto done; @@ -772,7 +772,7 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { char* filename = contents->data; FILE* f = fopen(filename, "rb"); if (f == NULL) { - fprintf(stderr, "%s: can't open %s: %s\n", + printf("%s: can't open %s: %s\n", name, filename, strerror(errno)); result = strdup(""); goto done; @@ -793,15 +793,15 @@ Value* WriteRawImageFn(const char* name, State* state, int argc, Expr* argv[]) { success = (wrote == contents->size); } if (!success) { - fprintf(stderr, "mtd_write_data to %s failed: %s\n", + printf("mtd_write_data to %s failed: %s\n", partition, strerror(errno)); } if (mtd_erase_blocks(ctx, -1) == -1) { - fprintf(stderr, "%s: error erasing blocks of %s\n", name, partition); + printf("%s: error erasing blocks of %s\n", name, partition); } if (mtd_write_close(ctx) != 0) { - fprintf(stderr, "%s: error closing write of %s\n", name, partition); + printf("%s: error closing write of %s\n", name, partition); } printf("%s %s partition\n", @@ -988,23 +988,23 @@ Value* RunProgramFn(const char* name, State* state, int argc, Expr* argv[]) { memcpy(args2, args, sizeof(char*) * argc); args2[argc] = NULL; - fprintf(stderr, "about to run program [%s] with %d args\n", args2[0], argc); + printf("about to run program [%s] with %d args\n", args2[0], argc); pid_t child = fork(); if (child == 0) { execv(args2[0], args2); - fprintf(stderr, "run_program: execv failed: %s\n", strerror(errno)); + printf("run_program: execv failed: %s\n", strerror(errno)); _exit(1); } int status; waitpid(child, &status, 0); if (WIFEXITED(status)) { if (WEXITSTATUS(status) != 0) { - fprintf(stderr, "run_program: child exited with status %d\n", + printf("run_program: child exited with status %d\n", WEXITSTATUS(status)); } } else if (WIFSIGNALED(status)) { - fprintf(stderr, "run_program: child terminated by signal %d\n", + printf("run_program: child terminated by signal %d\n", WTERMSIG(status)); } @@ -1053,7 +1053,7 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { } if (args[0]->size < 0) { - fprintf(stderr, "%s(): no file contents received", name); + printf("%s(): no file contents received", name); return StringValue(strdup("")); } uint8_t digest[SHA_DIGEST_SIZE]; @@ -1068,12 +1068,12 @@ Value* Sha1CheckFn(const char* name, State* state, int argc, Expr* argv[]) { uint8_t* arg_digest = malloc(SHA_DIGEST_SIZE); for (i = 1; i < argc; ++i) { if (args[i]->type != VAL_STRING) { - fprintf(stderr, "%s(): arg %d is not a string; skipping", + printf("%s(): arg %d is not a string; skipping", name, i); } else if (ParseSha1(args[i]->data, arg_digest) != 0) { // Warn about bad args and skip them. - fprintf(stderr, "%s(): error parsing \"%s\" as sha-1; skipping", - name, args[i]->data); + printf("%s(): error parsing \"%s\" as sha-1; skipping", + name, args[i]->data); } else if (memcmp(digest, arg_digest, SHA_DIGEST_SIZE) == 0) { break; } diff --git a/updater/updater.c b/updater/updater.c index 58ac27f9e..c7009feac 100644 --- a/updater/updater.c +++ b/updater/updater.c @@ -36,13 +36,14 @@ struct selabel_handle *sehandle; int main(int argc, char** argv) { // Various things log information to stdout or stderr more or less - // at random. The log file makes more sense if buffering is - // turned off so things appear in the right order. + // at random (though we've tried to standardize on stdout). The + // log file makes more sense if buffering is turned off so things + // appear in the right order. setbuf(stdout, NULL); setbuf(stderr, NULL); if (argc != 4) { - fprintf(stderr, "unexpected number of arguments (%d)\n", argc); + printf("unexpected number of arguments (%d)\n", argc); return 1; } @@ -50,7 +51,7 @@ int main(int argc, char** argv) { if ((version[0] != '1' && version[0] != '2' && version[0] != '3') || version[1] != '\0') { // We support version 1, 2, or 3. - fprintf(stderr, "wrong updater binary API; expected 1, 2, or 3; " + printf("wrong updater binary API; expected 1, 2, or 3; " "got %s\n", argv[1]); return 2; @@ -69,20 +70,20 @@ int main(int argc, char** argv) { int err; err = mzOpenZipArchive(package_data, &za); if (err != 0) { - fprintf(stderr, "failed to open package %s: %s\n", + printf("failed to open package %s: %s\n", package_data, strerror(err)); return 3; } const ZipEntry* script_entry = mzFindZipEntry(&za, SCRIPT_NAME); if (script_entry == NULL) { - fprintf(stderr, "failed to find %s in %s\n", SCRIPT_NAME, package_data); + printf("failed to find %s in %s\n", SCRIPT_NAME, package_data); return 4; } char* script = malloc(script_entry->uncompLen+1); if (!mzReadZipEntry(&za, script_entry, script, script_entry->uncompLen)) { - fprintf(stderr, "failed to read script from package\n"); + printf("failed to read script from package\n"); return 5; } script[script_entry->uncompLen] = '\0'; @@ -101,7 +102,7 @@ int main(int argc, char** argv) { yy_scan_string(script); int error = yyparse(&root, &error_count); if (error != 0 || error_count > 0) { - fprintf(stderr, "%d parse errors\n", error_count); + printf("%d parse errors\n", error_count); return 6; } @@ -112,7 +113,6 @@ int main(int argc, char** argv) { sehandle = selabel_open(SELABEL_CTX_FILE, seopts, 1); if (!sehandle) { - fprintf(stderr, "Warning: No file_contexts\n"); fprintf(cmd_pipe, "ui_print Warning: No file_contexts\n"); } @@ -131,10 +131,10 @@ int main(int argc, char** argv) { char* result = Evaluate(&state, root); if (result == NULL) { if (state.errmsg == NULL) { - fprintf(stderr, "script aborted (no error message)\n"); + printf("script aborted (no error message)\n"); fprintf(cmd_pipe, "ui_print script aborted (no error message)\n"); } else { - fprintf(stderr, "script aborted: %s\n", state.errmsg); + printf("script aborted: %s\n", state.errmsg); char* line = strtok(state.errmsg, "\n"); while (line) { fprintf(cmd_pipe, "ui_print %s\n", line); @@ -145,7 +145,7 @@ int main(int argc, char** argv) { free(state.errmsg); return 7; } else { - fprintf(stderr, "script result was [%s]\n", result); + fprintf(cmd_pipe, "ui_print script succeeded: result was [%s]\n", result); free(result); } -- cgit v1.2.3 From 6d0d7ac051a0338c0e07e239e742b92e5ab8ea07 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 9 Jul 2013 13:34:55 -0700 Subject: recovery: preserve recovery logs across cache wipes When doing a cache wipe or a factory reset (which includes a cache wipe), save any last* log files in the /cache/recovery directory and write them back after reformatting the partition, so that wiping data doesn't lose useful log information. Change-Id: I1f52ae9131760b5e752e136645c19f71b7b166ee --- recovery.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/recovery.cpp b/recovery.cpp index b7fb616ce..82cfc3f8d 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -61,6 +61,7 @@ static const struct option OPTIONS[] = { #define LAST_LOG_FILE "/cache/recovery/last_log" +static const char *CACHE_LOG_DIR = "/cache/recovery"; static const char *COMMAND_FILE = "/cache/recovery/command"; static const char *INTENT_FILE = "/cache/recovery/intent"; static const char *LOG_FILE = "/cache/recovery/log"; @@ -342,22 +343,95 @@ finish_recovery(const char *send_intent) { sync(); // For good measure. } +typedef struct _saved_log_file { + char* name; + struct stat st; + unsigned char* data; + struct _saved_log_file* next; +} saved_log_file; + static int erase_volume(const char *volume) { + bool is_cache = (strcmp(volume, CACHE_ROOT) == 0); + ui->SetBackground(RecoveryUI::ERASING); ui->SetProgressType(RecoveryUI::INDETERMINATE); + + saved_log_file* head = NULL; + + if (is_cache) { + // If we're reformatting /cache, we load any + // "/cache/recovery/last*" files into memory, so we can restore + // them after the reformat. + + ensure_path_mounted(volume); + + DIR* d; + struct dirent* de; + d = opendir(CACHE_LOG_DIR); + if (d) { + char path[PATH_MAX]; + strcpy(path, CACHE_LOG_DIR); + strcat(path, "/"); + int path_len = strlen(path); + while ((de = readdir(d)) != NULL) { + if (strncmp(de->d_name, "last", 4) == 0) { + saved_log_file* p = (saved_log_file*) malloc(sizeof(saved_log_file)); + strcpy(path+path_len, de->d_name); + p->name = strdup(path); + if (stat(path, &(p->st)) == 0) { + // truncate files to 512kb + if (p->st.st_size > (1 << 19)) { + p->st.st_size = 1 << 19; + } + p->data = (unsigned char*) malloc(p->st.st_size); + FILE* f = fopen(path, "rb"); + fread(p->data, 1, p->st.st_size, f); + fclose(f); + p->next = head; + head = p; + } else { + free(p); + } + } + } + closedir(d); + } else { + if (errno != ENOENT) { + printf("opendir failed: %s\n", strerror(errno)); + } + } + } + ui->Print("Formatting %s...\n", volume); ensure_path_unmounted(volume); + int result = format_volume(volume); + + if (is_cache) { + while (head) { + FILE* f = fopen_path(head->name, "wb"); + if (f) { + fwrite(head->data, 1, head->st.st_size, f); + fclose(f); + chmod(head->name, head->st.st_mode); + chown(head->name, head->st.st_uid, head->st.st_gid); + } + free(head->name); + free(head->data); + saved_log_file* temp = head->next; + free(head); + head = temp; + } - if (strcmp(volume, "/cache") == 0) { // Any part of the log we'd copied to cache is now gone. // Reset the pointer so we copy from the beginning of the temp // log. tmplog_offset = 0; + copy_logs(); } - return format_volume(volume); + return result; } static char* -- cgit v1.2.3 From 627eb30f73c29257acaeb6568f3da38880784f7c Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Wed, 17 Jul 2013 19:01:37 -0700 Subject: Update OTA installer to understand SELinux filesystem labels Modify the OTA installer to understand SELinux filesystem labels. We do this by introducing new set_perm2 / set_perm2_recursive calls, which understand SELinux filesystem labels. These filesystem labels are applied at the same time that we apply the UID / GID / permission changes. For compatibility, we preserve the behavior of the existing set_perm / set_perm_recursive calls. If the destination kernel doesn't support security labels, don't fail. SELinux isn't enabled on all kernels. Bug: 8985290 Change-Id: I99800499f01784199e4918a82e3e2db1089cf25b --- minzip/DirUtil.c | 9 +++++++-- minzip/DirUtil.h | 2 +- updater/install.c | 29 ++++++++++++++++++++++++----- 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/minzip/DirUtil.c b/minzip/DirUtil.c index 8dd5da1da..c120fa3cd 100644 --- a/minzip/DirUtil.c +++ b/minzip/DirUtil.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "DirUtil.h" @@ -237,7 +238,7 @@ dirUnlinkHierarchy(const char *path) int dirSetHierarchyPermissions(const char *path, - int uid, int gid, int dirMode, int fileMode) + int uid, int gid, int dirMode, int fileMode, const char* secontext) { struct stat st; if (lstat(path, &st)) { @@ -255,6 +256,10 @@ dirSetHierarchyPermissions(const char *path, return -1; } + if ((secontext != NULL) && lsetfilecon(path, secontext) && (errno != ENOTSUP)) { + return -1; + } + /* recurse over directory components */ if (S_ISDIR(st.st_mode)) { DIR *dir = opendir(path); @@ -271,7 +276,7 @@ dirSetHierarchyPermissions(const char *path, char dn[PATH_MAX]; snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name); - if (!dirSetHierarchyPermissions(dn, uid, gid, dirMode, fileMode)) { + if (!dirSetHierarchyPermissions(dn, uid, gid, dirMode, fileMode, secontext)) { errno = 0; } else if (errno == 0) { errno = -1; diff --git a/minzip/DirUtil.h b/minzip/DirUtil.h index a5cfa761b..3e12a0bf5 100644 --- a/minzip/DirUtil.h +++ b/minzip/DirUtil.h @@ -54,7 +54,7 @@ int dirUnlinkHierarchy(const char *path); * Sets directories to and files to . Skips symlinks. */ int dirSetHierarchyPermissions(const char *path, - int uid, int gid, int dirMode, int fileMode); + int uid, int gid, int dirMode, int fileMode, const char* secontext); #ifdef __cplusplus } diff --git a/updater/install.c b/updater/install.c index 9fa06a225..c81bbb59d 100644 --- a/updater/install.c +++ b/updater/install.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "cutils/misc.h" #include "cutils/properties.h" @@ -521,9 +522,10 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; - bool recursive = (strcmp(name, "set_perm_recursive") == 0); + bool recursive = (strcmp(name, "set_perm_recursive") == 0) || (strcmp(name, "set_perm2_recursive") == 0); + bool has_selabel = (strcmp(name, "set_perm2") == 0) || (strcmp(name, "set_perm2_recursive") == 0); - int min_args = 4 + (recursive ? 1 : 0); + int min_args = 4 + (has_selabel ? 1 : 0) + (recursive ? 1 : 0); if (argc < min_args) { return ErrorAbort(state, "%s() expects %d+ args, got %d", name, min_args, argc); @@ -562,8 +564,13 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { goto done; } - for (i = 4; i < argc; ++i) { - dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode); + char* secontext = NULL; + if (has_selabel) { + secontext = args[4]; + } + + for (i = 4 + (has_selabel ? 1 : 0); i < argc; ++i) { + dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode, secontext); } } else { int mode = strtoul(args[2], &end, 0); @@ -572,7 +579,12 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { goto done; } - for (i = 3; i < argc; ++i) { + char* secontext = NULL; + if (has_selabel) { + secontext = args[3]; + } + + for (i = 3 + (has_selabel ? 1 : 0); i < argc; ++i) { if (chown(args[i], uid, gid) < 0) { printf("%s: chown of %s to %d %d failed: %s\n", name, args[i], uid, gid, strerror(errno)); @@ -583,6 +595,11 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { name, args[i], mode, strerror(errno)); ++bad; } + if (has_selabel && lsetfilecon(args[i], secontext) && (errno != ENOTSUP)) { + printf("%s: lsetfilecon of %s to %s failed: %s\n", + name, args[i], secontext, strerror(errno)); + ++bad; + } } } result = strdup(""); @@ -1135,6 +1152,8 @@ void RegisterInstallFunctions() { RegisterFunction("symlink", SymlinkFn); RegisterFunction("set_perm", SetPermFn); RegisterFunction("set_perm_recursive", SetPermFn); + RegisterFunction("set_perm2", SetPermFn); + RegisterFunction("set_perm2_recursive", SetPermFn); RegisterFunction("getprop", GetPropFn); RegisterFunction("file_getprop", FileGetPropFn); -- cgit v1.2.3 From c0441d171914e59941ec4f815ae0aabf56d6504f Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Wed, 31 Jul 2013 11:28:24 -0700 Subject: notify about pending long press Recovery changes: - add a method to the UI class that is called when a key is held down long enough to be a "long press" (but before it is released). Device-specific subclasses can override this to indicate a long press. - do color selection for ScreenRecoveryUI's menu-and-log drawing function. Subclasses can override this to customize the colors they use for various elements. - Include the value of ro.build.display.id in the menu headers, so you can see on the screen what version of recovery you are running. Change-Id: I426a6daf892b9011638e2035aebfa2831d4f596d --- recovery.cpp | 14 ++++++-------- screen_ui.cpp | 48 ++++++++++++++++++++++++++++++++++++++---------- screen_ui.h | 5 +++++ ui.cpp | 41 +++++++++++++++++++++++++++++++++-------- ui.h | 21 ++++++++++++++++++++- 5 files changed, 102 insertions(+), 27 deletions(-) diff --git a/recovery.cpp b/recovery.cpp index c5a589cc6..38366b65a 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -75,6 +75,7 @@ static const char *SIDELOAD_TEMP_DIR = "/tmp/sideload"; RecoveryUI* ui = NULL; char* locale = NULL; +char recovery_version[PROPERTY_VALUE_MAX+1]; /* * The recovery tool communicates with the main system through /cache files. @@ -526,21 +527,17 @@ copy_sideloaded_package(const char* original_path) { static const char** prepend_title(const char* const* headers) { - const char* title[] = { "Android system recovery <" - EXPAND(RECOVERY_API_VERSION) "e>", - "", - NULL }; - // count the number of lines in our title, plus the // caller-provided headers. - int count = 0; + int count = 3; // our title has 3 lines const char* const* p; - for (p = title; *p; ++p, ++count); for (p = headers; *p; ++p, ++count); const char** new_headers = (const char**)malloc((count+1) * sizeof(char*)); const char** h = new_headers; - for (p = title; *p; ++p, ++h) *h = *p; + *(h++) = "Android system recovery <" EXPAND(RECOVERY_API_VERSION) "e>"; + *(h++) = recovery_version; + *(h++) = ""; for (p = headers; *p; ++p, ++h) *h = *p; *h = NULL; @@ -1022,6 +1019,7 @@ main(int argc, char **argv) { printf("\n"); property_list(print_property, NULL); + property_get("ro.build.display.id", recovery_version, ""); printf("\n"); int status = INSTALL_SUCCESS; diff --git a/screen_ui.cpp b/screen_ui.cpp index 93e260936..6a638582e 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -196,9 +196,29 @@ void ScreenRecoveryUI::draw_progress_locked() } } -#define C_HEADER 247,0,6 -#define C_MENU 0,106,157 -#define C_LOG 249,194,0 +void ScreenRecoveryUI::SetColor(UIElement e) { + switch (e) { + case HEADER: + gr_color(247, 0, 6, 255); + break; + case MENU: + case MENU_SEL_BG: + gr_color(0, 106, 157, 255); + break; + case MENU_SEL_FG: + gr_color(255, 255, 255, 255); + break; + case LOG: + gr_color(249, 194, 0, 255); + break; + case TEXT_FILL: + gr_color(0, 0, 0, 160); + break; + default: + gr_color(255, 255, 255, 255); + break; + } +} // Redraw everything on the screen. Does not flip pages. // Should only be called with updateMutex locked. @@ -208,37 +228,38 @@ void ScreenRecoveryUI::draw_screen_locked() draw_progress_locked(); if (show_text) { - gr_color(0, 0, 0, 160); + SetColor(TEXT_FILL); gr_fill(0, 0, gr_fb_width(), gr_fb_height()); int y = 0; int i = 0; if (show_menu) { - gr_color(C_HEADER, 255); + SetColor(HEADER); for (; i < menu_top + menu_items; ++i) { - if (i == menu_top) gr_color(C_MENU, 255); + if (i == menu_top) SetColor(MENU); if (i == menu_top + menu_sel) { // draw the highlight bar + SetColor(MENU_SEL_BG); gr_fill(0, y-2, gr_fb_width(), y+char_height+2); // white text of selected item - gr_color(255, 255, 255, 255); + SetColor(MENU_SEL_FG); if (menu[i][0]) gr_text(4, y, menu[i], 1); - gr_color(C_MENU, 255); + SetColor(MENU); } else { if (menu[i][0]) gr_text(4, y, menu[i], i < menu_top); } y += char_height+4; } - gr_color(C_MENU, 255); + SetColor(MENU); y += 4; gr_fill(0, y, gr_fb_width(), y+2); y += 4; ++i; } - gr_color(C_LOG, 255); + SetColor(LOG); // display from the bottom up, until we hit the top of the // screen, the bottom of the menu, or we've displayed the @@ -585,3 +606,10 @@ void ScreenRecoveryUI::ShowText(bool visible) update_screen_locked(); pthread_mutex_unlock(&updateMutex); } + +void ScreenRecoveryUI::Redraw() +{ + pthread_mutex_lock(&updateMutex); + update_screen_locked(); + pthread_mutex_unlock(&updateMutex); +} diff --git a/screen_ui.h b/screen_ui.h index fe0de46e8..0bd220f74 100644 --- a/screen_ui.h +++ b/screen_ui.h @@ -53,6 +53,11 @@ class ScreenRecoveryUI : public RecoveryUI { int SelectMenu(int sel); void EndMenu(); + void Redraw(); + + enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_FG, LOG, TEXT_FILL }; + virtual void SetColor(UIElement e); + private: Icon currentIcon; int installingFrame; diff --git a/ui.cpp b/ui.cpp index 65f402821..cece02d31 100644 --- a/ui.cpp +++ b/ui.cpp @@ -46,7 +46,8 @@ static RecoveryUI* self = NULL; RecoveryUI::RecoveryUI() : key_queue_len(0), key_last_down(-1), - key_down_time(0) { + key_long_press(false), + key_down_count(0) { pthread_mutex_init(&key_queue_mutex, NULL); pthread_cond_init(&key_queue_cond, NULL); self = this; @@ -112,19 +113,22 @@ void RecoveryUI::process_key(int key_code, int updown) { bool register_key = false; bool long_press = false; - const long long_threshold = CLOCKS_PER_SEC * 750 / 1000; - pthread_mutex_lock(&key_queue_mutex); key_pressed[key_code] = updown; if (updown) { + ++key_down_count; key_last_down = key_code; - key_down_time = clock(); + key_long_press = false; + pthread_t th; + key_timer_t* info = new key_timer_t; + info->ui = this; + info->key_code = key_code; + info->count = key_down_count; + pthread_create(&th, NULL, &RecoveryUI::time_key_helper, info); + pthread_detach(th); } else { if (key_last_down == key_code) { - long duration = clock() - key_down_time; - if (duration > long_threshold) { - long_press = true; - } + long_press = key_long_press; register_key = true; } key_last_down = -1; @@ -152,6 +156,24 @@ void RecoveryUI::process_key(int key_code, int updown) { } } +void* RecoveryUI::time_key_helper(void* cookie) { + key_timer_t* info = (key_timer_t*) cookie; + info->ui->time_key(info->key_code, info->count); + delete info; + return NULL; +} + +void RecoveryUI::time_key(int key_code, int count) { + usleep(750000); // 750 ms == "long" + bool long_press = false; + pthread_mutex_lock(&key_queue_mutex); + if (key_last_down == key_code && key_down_count == count) { + long_press = key_long_press = true; + } + pthread_mutex_unlock(&key_queue_mutex); + if (long_press) KeyLongPress(key_code); +} + void RecoveryUI::EnqueueKey(int key_code) { pthread_mutex_lock(&key_queue_mutex); const int queue_max = sizeof(key_queue) / sizeof(key_queue[0]); @@ -242,3 +264,6 @@ RecoveryUI::KeyAction RecoveryUI::CheckKey(int key) { void RecoveryUI::NextCheckKeyIsLong(bool is_long_press) { } + +void RecoveryUI::KeyLongPress(int key) { +} diff --git a/ui.h b/ui.h index aca7b7b87..6c8987a33 100644 --- a/ui.h +++ b/ui.h @@ -80,8 +80,17 @@ class RecoveryUI { enum KeyAction { ENQUEUE, TOGGLE, REBOOT, IGNORE }; virtual KeyAction CheckKey(int key); + // Called immediately before each call to CheckKey(), tell you if + // the key was long-pressed. virtual void NextCheckKeyIsLong(bool is_long_press); + // Called when a key is held down long enough to have been a + // long-press (but before the key is released). This means that + // if the key is eventually registered (released without any other + // keys being pressed in the meantime), NextCheckKeyIsLong() will + // be called with "true". + virtual void KeyLongPress(int key); + // --- menu display --- // Display some header text followed by a menu of items, which appears @@ -108,15 +117,25 @@ private: int key_queue[256], key_queue_len; char key_pressed[KEY_MAX + 1]; // under key_queue_mutex int key_last_down; // under key_queue_mutex - clock_t key_down_time; // under key_queue_mutex + bool key_long_press; // under key_queue_mutex + int key_down_count; // under key_queue_mutex int rel_sum; + typedef struct { + RecoveryUI* ui; + int key_code; + int count; + } key_timer_t; + pthread_t input_t; static void* input_thread(void* cookie); static int input_callback(int fd, short revents, void* data); void process_key(int key_code, int updown); bool usb_connected(); + + static void* time_key_helper(void* cookie); + void time_key(int key_code, int count); }; #endif // RECOVERY_UI_H -- cgit v1.2.3 From 239ac6abac4524be93fce710360c0512c6cc2ab3 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 20 Aug 2013 16:03:25 -0700 Subject: recovery: install packages in a known mount environment When installing a package, we should have /tmp and /cache mounted and nothing else. Ensure this is true by explicitly mounting them and unmounting everything else as the first step of every install. Also fix an error in the progress bar that crops up when you do multiple package installs in one instance of recovery. Change-Id: I4837ed707cb419ddd3d9f6188b6355ba1bcfe2b2 --- install.cpp | 15 ++++++++++----- recovery.cpp | 5 ----- roots.cpp | 19 +++++++++++++++++++ roots.h | 4 ++++ screen_ui.cpp | 3 ++- 5 files changed, 35 insertions(+), 11 deletions(-) diff --git a/install.cpp b/install.cpp index e1ab848f6..797a525fd 100644 --- a/install.cpp +++ b/install.cpp @@ -180,7 +180,9 @@ really_install_package(const char *path, int* wipe_cache) { ui->SetBackground(RecoveryUI::INSTALLING_UPDATE); ui->Print("Finding update package...\n"); - ui->SetProgressType(RecoveryUI::INDETERMINATE); + // Give verification half the progress bar... + ui->SetProgressType(RecoveryUI::DETERMINATE); + ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME); LOGI("Update location: %s\n", path); if (ensure_path_mounted(path) != 0) { @@ -198,10 +200,7 @@ really_install_package(const char *path, int* wipe_cache) } LOGI("%d key(s) loaded from %s\n", numKeys, PUBLIC_KEYS_FILE); - // Give verification half the progress bar... ui->Print("Verifying update package...\n"); - ui->SetProgressType(RecoveryUI::DETERMINATE); - ui->ShowProgress(VERIFICATION_PROGRESS_FRACTION, VERIFICATION_PROGRESS_TIME); int err; err = verify_file(path, loadedKeys, numKeys); @@ -237,7 +236,13 @@ install_package(const char* path, int* wipe_cache, const char* install_file) } else { LOGE("failed to open last_install: %s\n", strerror(errno)); } - int result = really_install_package(path, wipe_cache); + int result; + if (setup_install_mounts() != 0) { + LOGE("failed to set up expected mounts for install; aborting\n"); + result = INSTALL_ERROR; + } else { + result = really_install_package(path, wipe_cache); + } if (install_log) { fputc(result == INSTALL_SUCCESS ? '1' : '0', install_log); fputc('\n', install_log); diff --git a/recovery.cpp b/recovery.cpp index 38366b65a..654a66526 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -811,10 +811,6 @@ prompt_and_wait(Device* device, int status) { break; case Device::APPLY_EXT: - // Some packages expect /cache to be mounted (eg, - // standard incremental packages expect to use /cache - // as scratch space). - ensure_path_mounted(CACHE_ROOT); status = update_directory(SDCARD_ROOT, SDCARD_ROOT, &wipe_cache, device); if (status == INSTALL_SUCCESS && wipe_cache) { ui->Print("\n-- Wiping cache (at package request)...\n"); @@ -860,7 +856,6 @@ prompt_and_wait(Device* device, int status) { break; case Device::APPLY_ADB_SIDELOAD: - ensure_path_mounted(CACHE_ROOT); status = apply_from_adb(ui, &wipe_cache, TEMPORARY_INSTALL_FILE); if (status >= 0) { if (status != INSTALL_SUCCESS) { diff --git a/roots.cpp b/roots.cpp index 09471225d..113dba1bd 100644 --- a/roots.cpp +++ b/roots.cpp @@ -202,3 +202,22 @@ int format_volume(const char* volume) { LOGE("format_volume: fs_type \"%s\" unsupported\n", v->fs_type); return -1; } + +int setup_install_mounts() { + if (fstab == NULL) { + LOGE("can't set up install mounts: no fstab loaded\n"); + return -1; + } + for (int i = 0; i < fstab->num_entries; ++i) { + Volume* v = fstab->recs + i; + + if (strcmp(v->mount_point, "/tmp") == 0 || + strcmp(v->mount_point, "/cache") == 0) { + if (ensure_path_mounted(v->mount_point) != 0) return -1; + + } else { + if (ensure_path_unmounted(v->mount_point) != 0) return -1; + } + } + return 0; +} diff --git a/roots.h b/roots.h index 8abe18fb7..230d9ded3 100644 --- a/roots.h +++ b/roots.h @@ -42,6 +42,10 @@ int ensure_path_unmounted(const char* path); // it is mounted. int format_volume(const char* volume); +// Ensure that all and only the volumes that packages expect to find +// mounted (/tmp and /cache) are mounted. Returns 0 on success. +int setup_install_mounts(); + #ifdef __cplusplus } #endif diff --git a/screen_ui.cpp b/screen_ui.cpp index 6a638582e..8376341c3 100644 --- a/screen_ui.cpp +++ b/screen_ui.cpp @@ -467,10 +467,11 @@ void ScreenRecoveryUI::SetProgressType(ProgressType type) pthread_mutex_lock(&updateMutex); if (progressBarType != type) { progressBarType = type; - update_progress_locked(); } progressScopeStart = 0; + progressScopeSize = 0; progress = 0; + update_progress_locked(); pthread_mutex_unlock(&updateMutex); } -- cgit v1.2.3 From 77ea71d6a85a93c9bf423466e87661b1bf67c512 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Fri, 30 Aug 2013 12:20:16 -0700 Subject: recovery: fix rebooting Change I84c0513acb549720cb0e8c9fcbda0050f5c396f5 moved reboot functionality into init but did not update the recovery partition; so "adb reboot" and /system/bin/reboot in recovery are both broken. Change-Id: Ie2d14627a686ffb5064256b6c399723636dff116 --- etc/init.rc | 3 +++ recovery.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/etc/init.rc b/etc/init.rc index b26d2ae73..9d1da1d6a 100644 --- a/etc/init.rc +++ b/etc/init.rc @@ -38,6 +38,9 @@ on boot class_start default +on property:sys.powerctl=* + powerctl ${sys.powerctl} + service ueventd /sbin/ueventd critical diff --git a/recovery.cpp b/recovery.cpp index 654a66526..b78339314 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -1062,6 +1062,6 @@ main(int argc, char **argv) { // Otherwise, get ready to boot the main system... finish_recovery(send_intent); ui->Print("Rebooting...\n"); - android_reboot(ANDROID_RB_RESTART, 0, 0); + property_set(ANDROID_RB_PROPERTY, ""); return EXIT_SUCCESS; } -- cgit v1.2.3 From 3b5a987cd7fd76c038e9875b430028216d21ace3 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 3 Sep 2013 14:29:54 -0700 Subject: recovery: fix use of init reboot method We need to set the system property to "reboot,", not an empty string. Bug: 10605007 Change-Id: I776e0d273764cf254651ab2b25c2743395b990e0 --- recovery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recovery.cpp b/recovery.cpp index b78339314..d803cadf1 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -1062,6 +1062,6 @@ main(int argc, char **argv) { // Otherwise, get ready to boot the main system... finish_recovery(send_intent); ui->Print("Rebooting...\n"); - property_set(ANDROID_RB_PROPERTY, ""); + property_set(ANDROID_RB_PROPERTY, "reboot,"); return EXIT_SUCCESS; } -- cgit v1.2.3 From 15ae0e7867507f3bde3cd7061fbad933d1fe059c Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Tue, 3 Sep 2013 14:29:54 -0700 Subject: recovery: fix use of init reboot method We need to set the system property to "reboot,", not an empty string. Bug: 10605007 Change-Id: I776e0d273764cf254651ab2b25c2743395b990e0 --- recovery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recovery.cpp b/recovery.cpp index b78339314..d803cadf1 100644 --- a/recovery.cpp +++ b/recovery.cpp @@ -1062,6 +1062,6 @@ main(int argc, char **argv) { // Otherwise, get ready to boot the main system... finish_recovery(send_intent); ui->Print("Rebooting...\n"); - property_set(ANDROID_RB_PROPERTY, ""); + property_set(ANDROID_RB_PROPERTY, "reboot,"); return EXIT_SUCCESS; } -- cgit v1.2.3 From 3328e3bc81161c2a57ea94d304162276facdd826 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Mon, 9 Sep 2013 10:47:14 -0700 Subject: Revert "Update OTA installer to understand SELinux filesystem labels" This reverts commit 627eb30f73c29257acaeb6568f3da38880784f7c. Bug: 10183961 Bug: 10186213 --- minzip/DirUtil.c | 9 ++------- minzip/DirUtil.h | 2 +- updater/install.c | 29 +++++------------------------ 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/minzip/DirUtil.c b/minzip/DirUtil.c index c120fa3cd..8dd5da1da 100644 --- a/minzip/DirUtil.c +++ b/minzip/DirUtil.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "DirUtil.h" @@ -238,7 +237,7 @@ dirUnlinkHierarchy(const char *path) int dirSetHierarchyPermissions(const char *path, - int uid, int gid, int dirMode, int fileMode, const char* secontext) + int uid, int gid, int dirMode, int fileMode) { struct stat st; if (lstat(path, &st)) { @@ -256,10 +255,6 @@ dirSetHierarchyPermissions(const char *path, return -1; } - if ((secontext != NULL) && lsetfilecon(path, secontext) && (errno != ENOTSUP)) { - return -1; - } - /* recurse over directory components */ if (S_ISDIR(st.st_mode)) { DIR *dir = opendir(path); @@ -276,7 +271,7 @@ dirSetHierarchyPermissions(const char *path, char dn[PATH_MAX]; snprintf(dn, sizeof(dn), "%s/%s", path, de->d_name); - if (!dirSetHierarchyPermissions(dn, uid, gid, dirMode, fileMode, secontext)) { + if (!dirSetHierarchyPermissions(dn, uid, gid, dirMode, fileMode)) { errno = 0; } else if (errno == 0) { errno = -1; diff --git a/minzip/DirUtil.h b/minzip/DirUtil.h index 3e12a0bf5..a5cfa761b 100644 --- a/minzip/DirUtil.h +++ b/minzip/DirUtil.h @@ -54,7 +54,7 @@ int dirUnlinkHierarchy(const char *path); * Sets directories to and files to . Skips symlinks. */ int dirSetHierarchyPermissions(const char *path, - int uid, int gid, int dirMode, int fileMode, const char* secontext); + int uid, int gid, int dirMode, int fileMode); #ifdef __cplusplus } diff --git a/updater/install.c b/updater/install.c index c81bbb59d..9fa06a225 100644 --- a/updater/install.c +++ b/updater/install.c @@ -27,7 +27,6 @@ #include #include #include -#include #include "cutils/misc.h" #include "cutils/properties.h" @@ -522,10 +521,9 @@ Value* SymlinkFn(const char* name, State* state, int argc, Expr* argv[]) { Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { char* result = NULL; - bool recursive = (strcmp(name, "set_perm_recursive") == 0) || (strcmp(name, "set_perm2_recursive") == 0); - bool has_selabel = (strcmp(name, "set_perm2") == 0) || (strcmp(name, "set_perm2_recursive") == 0); + bool recursive = (strcmp(name, "set_perm_recursive") == 0); - int min_args = 4 + (has_selabel ? 1 : 0) + (recursive ? 1 : 0); + int min_args = 4 + (recursive ? 1 : 0); if (argc < min_args) { return ErrorAbort(state, "%s() expects %d+ args, got %d", name, min_args, argc); @@ -564,13 +562,8 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { goto done; } - char* secontext = NULL; - if (has_selabel) { - secontext = args[4]; - } - - for (i = 4 + (has_selabel ? 1 : 0); i < argc; ++i) { - dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode, secontext); + for (i = 4; i < argc; ++i) { + dirSetHierarchyPermissions(args[i], uid, gid, dir_mode, file_mode); } } else { int mode = strtoul(args[2], &end, 0); @@ -579,12 +572,7 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { goto done; } - char* secontext = NULL; - if (has_selabel) { - secontext = args[3]; - } - - for (i = 3 + (has_selabel ? 1 : 0); i < argc; ++i) { + for (i = 3; i < argc; ++i) { if (chown(args[i], uid, gid) < 0) { printf("%s: chown of %s to %d %d failed: %s\n", name, args[i], uid, gid, strerror(errno)); @@ -595,11 +583,6 @@ Value* SetPermFn(const char* name, State* state, int argc, Expr* argv[]) { name, args[i], mode, strerror(errno)); ++bad; } - if (has_selabel && lsetfilecon(args[i], secontext) && (errno != ENOTSUP)) { - printf("%s: lsetfilecon of %s to %s failed: %s\n", - name, args[i], secontext, strerror(errno)); - ++bad; - } } } result = strdup(""); @@ -1152,8 +1135,6 @@ void RegisterInstallFunctions() { RegisterFunction("symlink", SymlinkFn); RegisterFunction("set_perm", SetPermFn); RegisterFunction("set_perm_recursive", SetPermFn); - RegisterFunction("set_perm2", SetPermFn); - RegisterFunction("set_perm2_recursive", SetPermFn); RegisterFunction("getprop", GetPropFn); RegisterFunction("file_getprop", FileGetPropFn); -- cgit v1.2.3 From 5dbdef0e5b8a841fadc64d016d10ce81a962b284 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Sat, 7 Sep 2013 14:41:06 -0700 Subject: updater: introduce and set_metadata and set_metadata_recursive Introduce two new updater functions: * set_metadata * set_metadata_recursive Long term, these functions are intended to be more flexible replacements for the following methods: * set_perm * set_perm_recursive Usage: set_metadata("filename", "key1", "value1", "key2", "value2", ...) set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...) Description: set_metadata() and set_metadata_recursive() set the attributes on a file/directory according to the key/value pairs provided. Today, the following keys are supported: * uid * gid * mode (set_perm_extd only) * fmode (set_perm_extd_recursive only) * dmode (set_perm_extd_recursive only) * selabel * capabilities Unknown keys are logged as warnings, but are not fatal errors. Examples: * set_metadata("/system/bin/netcfg", "selabel", "u:object_r:system_file:s0"); This sets the SELinux label of /system/bin/netcfg to u:object_r:system_file:s0. No other changes occur. * set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); This sets /system/bin/netcfg to uid=0, gid=3003, mode=02750, selinux label=u:object_r:system_file:s0, and clears the capabilities associated with the file. * set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); All files and directories under /system are set to uid=0, gid=0, and selinux label=u:object_r:system_file:s0. Directories are set to mode=0755. Files are set to mode=0644 and all capabilities are cleared. Bug: 10183961 Bug: 10186213 Bug: 8985290 Change-Id: Ifdcf186a7ed45265511dc493c4036e1ac5e3d0af --- updater/install.c | 274 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) diff --git a/updater/install.c b/updater/install.c index 9fa06a225..770dbd09e 100644 --- a/updater/install.c +++ b/updater/install.c @@ -27,6 +27,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "cutils/misc.h" #include "cutils/properties.h" @@ -600,6 +606,259 @@ done: return StringValue(result); } +struct perm_parsed_args { + bool has_uid; + uid_t uid; + bool has_gid; + gid_t gid; + bool has_mode; + mode_t mode; + bool has_fmode; + mode_t fmode; + bool has_dmode; + mode_t dmode; + bool has_selabel; + char* selabel; + bool has_capabilities; + uint64_t capabilities; +}; + +static struct perm_parsed_args ParsePermArgs(int argc, char** args) { + int i; + struct perm_parsed_args parsed; + int bad = 0; + static int max_warnings = 20; + + memset(&parsed, 0, sizeof(parsed)); + + for (i = 1; i < argc; i += 2) { + if (strcmp("uid", args[i]) == 0) { + int64_t uid; + if (sscanf(args[i+1], "%" SCNd64, &uid) == 1) { + parsed.uid = uid; + parsed.has_uid = true; + } else { + printf("ParsePermArgs: invalid UID \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("gid", args[i]) == 0) { + int64_t gid; + if (sscanf(args[i+1], "%" SCNd64, &gid) == 1) { + parsed.gid = gid; + parsed.has_gid = true; + } else { + printf("ParsePermArgs: invalid GID \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("mode", args[i]) == 0) { + int32_t mode; + if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + parsed.mode = mode; + parsed.has_mode = true; + } else { + printf("ParsePermArgs: invalid mode \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("dmode", args[i]) == 0) { + int32_t mode; + if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + parsed.dmode = mode; + parsed.has_dmode = true; + } else { + printf("ParsePermArgs: invalid dmode \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("fmode", args[i]) == 0) { + int32_t mode; + if (sscanf(args[i+1], "%" SCNi32, &mode) == 1) { + parsed.fmode = mode; + parsed.has_fmode = true; + } else { + printf("ParsePermArgs: invalid fmode \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("capabilities", args[i]) == 0) { + int64_t capabilities; + if (sscanf(args[i+1], "%" SCNi64, &capabilities) == 1) { + parsed.capabilities = capabilities; + parsed.has_capabilities = true; + } else { + printf("ParsePermArgs: invalid capabilities \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (strcmp("selabel", args[i]) == 0) { + if (args[i+1][0] != '\0') { + parsed.selabel = args[i+1]; + parsed.has_selabel = true; + } else { + printf("ParsePermArgs: invalid selabel \"%s\"\n", args[i + 1]); + bad++; + } + continue; + } + if (max_warnings != 0) { + printf("ParsedPermArgs: unknown key \"%s\", ignoring\n", args[i]); + max_warnings--; + if (max_warnings == 0) { + printf("ParsedPermArgs: suppressing further warnings\n"); + } + } + } + return parsed; +} + +static int ApplyParsedPerms( + const char* filename, + const struct stat *statptr, + struct perm_parsed_args parsed) +{ + int bad = 0; + + if (parsed.has_uid) { + if (chown(filename, parsed.uid, -1) < 0) { + printf("ApplyParsedPerms: chown of %s to %d failed: %s\n", + filename, parsed.uid, strerror(errno)); + bad++; + } + } + + if (parsed.has_gid) { + if (chown(filename, -1, parsed.gid) < 0) { + printf("ApplyParsedPerms: chgrp of %s to %d failed: %s\n", + filename, parsed.gid, strerror(errno)); + bad++; + } + } + + if (parsed.has_mode) { + if (chmod(filename, parsed.mode) < 0) { + printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", + filename, parsed.mode, strerror(errno)); + bad++; + } + } + + if (parsed.has_dmode && S_ISDIR(statptr->st_mode)) { + if (chmod(filename, parsed.dmode) < 0) { + printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", + filename, parsed.dmode, strerror(errno)); + bad++; + } + } + + if (parsed.has_fmode && S_ISREG(statptr->st_mode)) { + if (chmod(filename, parsed.fmode) < 0) { + printf("ApplyParsedPerms: chmod of %s to %d failed: %s\n", + filename, parsed.fmode, strerror(errno)); + bad++; + } + } + + if (parsed.has_selabel) { + // TODO: Don't silently ignore ENOTSUP + if (lsetfilecon(filename, parsed.selabel) && (errno != ENOTSUP)) { + printf("ApplyParsedPerms: lsetfilecon of %s to %s failed: %s\n", + filename, parsed.selabel, strerror(errno)); + bad++; + } + } + + if (parsed.has_capabilities && S_ISREG(statptr->st_mode)) { + if (parsed.capabilities == 0) { + if ((removexattr(filename, XATTR_NAME_CAPS) == -1) && (errno != ENODATA)) { + // Report failure unless it's ENODATA (attribute not set) + printf("ApplyParsedPerms: removexattr of %s to %" PRIx64 " failed: %s\n", + filename, parsed.capabilities, strerror(errno)); + bad++; + } + } else { + struct vfs_cap_data cap_data; + memset(&cap_data, 0, sizeof(cap_data)); + cap_data.magic_etc = VFS_CAP_REVISION | VFS_CAP_FLAGS_EFFECTIVE; + cap_data.data[0].permitted = (uint32_t) (parsed.capabilities & 0xffffffff); + cap_data.data[0].inheritable = 0; + cap_data.data[1].permitted = (uint32_t) (parsed.capabilities >> 32); + cap_data.data[1].inheritable = 0; + if (setxattr(filename, XATTR_NAME_CAPS, &cap_data, sizeof(cap_data), 0) < 0) { + printf("ApplyParsedPerms: setcap of %s to %" PRIx64 " failed: %s\n", + filename, parsed.capabilities, strerror(errno)); + bad++; + } + } + } + + return bad; +} + +// nftw doesn't allow us to pass along context, so we need to use +// global variables. *sigh* +static struct perm_parsed_args recursive_parsed_args; + +static int do_SetMetadataRecursive(const char* filename, const struct stat *statptr, + int fileflags, struct FTW *pfwt) { + return ApplyParsedPerms(filename, statptr, recursive_parsed_args); +} + +static Value* SetMetadataFn(const char* name, State* state, int argc, Expr* argv[]) { + int i; + int bad = 0; + static int nwarnings = 0; + struct stat sb; + Value* result = NULL; + + bool recursive = (strcmp(name, "set_metadata_recursive") == 0); + + if ((argc % 2) != 1) { + return ErrorAbort(state, "%s() expects an odd number of arguments, got %d", + name, argc); + } + + char** args = ReadVarArgs(state, argc, argv); + if (args == NULL) return NULL; + + if (lstat(args[0], &sb) == -1) { + result = ErrorAbort(state, "%s: Error on lstat of \"%s\": %s", name, args[0], strerror(errno)); + goto done; + } + + struct perm_parsed_args parsed = ParsePermArgs(argc, args); + + if (recursive) { + recursive_parsed_args = parsed; + bad += nftw(args[0], do_SetMetadataRecursive, 30, FTW_CHDIR | FTW_DEPTH | FTW_PHYS); + memset(&recursive_parsed_args, 0, sizeof(recursive_parsed_args)); + } else { + bad += ApplyParsedPerms(args[0], &sb, parsed); + } + +done: + for (i = 0; i < argc; ++i) { + free(args[i]); + } + free(args); + + if (result != NULL) { + return result; + } + + if (bad > 0) { + return ErrorAbort(state, "%s: some changes failed", name); + } + + return StringValue(strdup("")); +} Value* GetPropFn(const char* name, State* state, int argc, Expr* argv[]) { if (argc != 1) { @@ -1133,9 +1392,24 @@ void RegisterInstallFunctions() { RegisterFunction("package_extract_dir", PackageExtractDirFn); RegisterFunction("package_extract_file", PackageExtractFileFn); RegisterFunction("symlink", SymlinkFn); + + // Maybe, at some future point, we can delete these functions? They have been + // replaced by perm_set and perm_set_recursive. RegisterFunction("set_perm", SetPermFn); RegisterFunction("set_perm_recursive", SetPermFn); + // Usage: + // set_metadata("filename", "key1", "value1", "key2", "value2", ...) + // Example: + // set_metadata("/system/bin/netcfg", "uid", 0, "gid", 3003, "mode", 02750, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); + RegisterFunction("set_metadata", SetMetadataFn); + + // Usage: + // set_metadata_recursive("dirname", "key1", "value1", "key2", "value2", ...) + // Example: + // set_metadata_recursive("/system", "uid", 0, "gid", 0, "fmode", 0644, "dmode", 0755, "selabel", "u:object_r:system_file:s0", "capabilities", 0x0); + RegisterFunction("set_metadata_recursive", SetMetadataFn); + RegisterFunction("getprop", GetPropFn); RegisterFunction("file_getprop", FileGetPropFn); RegisterFunction("write_raw_image", WriteRawImageFn); -- cgit v1.2.3 From e461251e2caa5561cf6a315bffaebfd4eb896b1d Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Tue, 10 Sep 2013 15:34:19 -0700 Subject: Don't apply permission changes to symlink. Bug: 10183961 Bug: 10186213 Bug: 8985290 Change-Id: I57cb14af59682c5f25f1e091564548bdbf20f74e --- updater/install.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/updater/install.c b/updater/install.c index 770dbd09e..0a859452a 100644 --- a/updater/install.c +++ b/updater/install.c @@ -726,6 +726,11 @@ static int ApplyParsedPerms( { int bad = 0; + /* ignore symlinks */ + if (S_ISLNK(statptr->st_mode)) { + return 0; + } + if (parsed.has_uid) { if (chown(filename, parsed.uid, -1) < 0) { printf("ApplyParsedPerms: chown of %s to %d failed: %s\n", -- cgit v1.2.3 From d456944f02cf41af63f4a32a974721c8dd6a0f66 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Tue, 10 Sep 2013 15:34:19 -0700 Subject: Don't apply permission changes to symlink. Bug: 10183961 Bug: 10186213 Bug: 8985290 Change-Id: I57cb14af59682c5f25f1e091564548bdbf20f74e --- updater/install.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/updater/install.c b/updater/install.c index 770dbd09e..0a859452a 100644 --- a/updater/install.c +++ b/updater/install.c @@ -726,6 +726,11 @@ static int ApplyParsedPerms( { int bad = 0; + /* ignore symlinks */ + if (S_ISLNK(statptr->st_mode)) { + return 0; + } + if (parsed.has_uid) { if (chown(filename, parsed.uid, -1) < 0) { printf("ApplyParsedPerms: chown of %s to %d failed: %s\n", -- cgit v1.2.3 From cc2958fd7f32f79d1a034eee005e04afeb310a87 Mon Sep 17 00:00:00 2001 From: Doug Zongker Date: Wed, 11 Sep 2013 13:24:32 -0700 Subject: fix secure adb in recovery Recovery's init.rc was missing a line (added to the main system's init.rc in change Ic97fd464440ff4a29fc9da7ad15949ac5215ade3) is required for secure adb to work. Change-Id: Id79b94d2abb4cbe3cca7cabeb4bc5faf7205e56b --- etc/init.rc | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/init.rc b/etc/init.rc index 9d1da1d6a..175489066 100644 --- a/etc/init.rc +++ b/etc/init.rc @@ -51,6 +51,7 @@ service recovery /sbin/recovery service adbd /sbin/adbd recovery disabled + socket adbd stream 660 system system # Always start adbd on userdebug and eng builds on property:ro.debuggable=1 -- cgit v1.2.3 From a2a1ce823b8c76451ee2b38155b347b0c2ced714 Mon Sep 17 00:00:00 2001 From: Michael Runge Date: Wed, 2 Oct 2013 16:17:37 -0700 Subject: Allow child classes to override the overlay location for the update image. b/10952479 Change-Id: I59bb834f271f702fb529054dab7926b816fa35cc --- screen_ui.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/screen_ui.h b/screen_ui.h index 0bd220f74..fc35d95b6 100644 --- a/screen_ui.h +++ b/screen_ui.h @@ -58,6 +58,9 @@ class ScreenRecoveryUI : public RecoveryUI { enum UIElement { HEADER, MENU, MENU_SEL_BG, MENU_SEL_FG, LOG, TEXT_FILL }; virtual void SetColor(UIElement e); + protected: + int install_overlay_offset_x, install_overlay_offset_y; + private: Icon currentIcon; int installingFrame; @@ -99,7 +102,6 @@ class ScreenRecoveryUI : public RecoveryUI { int animation_fps; int indeterminate_frames; int installing_frames; - int install_overlay_offset_x, install_overlay_offset_y; int overlay_offset_x, overlay_offset_y; void draw_install_overlay_locked(int frame); -- cgit v1.2.3