Calculate correct checksum.

To maintain parity with fs-verity, we need to calculate checksums
according to https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#fs-verity-descriptor

Bug: 233217301
Fixes: 233217301
Test: atest ChecksumsTest
Change-Id: Ie0108f12ba988536a1d2fd9dddf1614681026f7c
This commit is contained in:
Alex Buynytskyy
2022-05-19 10:38:47 -07:00
parent 851b2e6a4d
commit 984e7524ea
2 changed files with 46 additions and 9 deletions

View File

@@ -77,6 +77,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.security.DigestException;
import java.security.InvalidParameterException;
@@ -584,7 +585,7 @@ public class ApkChecksums {
});
checksums.put(TYPE_WHOLE_MERKLE_ROOT_4K_SHA256,
new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256,
generatedRootHash));
verityHashForFile(file, generatedRootHash)));
} catch (IOException | NoSuchAlgorithmException | DigestException e) {
Slog.e(TAG, "Error calculating WHOLE_MERKLE_ROOT_4K_SHA256", e);
}
@@ -649,19 +650,20 @@ public class ApkChecksums {
// Skip /product folder.
// TODO(b/231354111): remove this hack once we are allowed to change SELinux rules.
if (!containsFile(Environment.getProductDirectory(), filePath)) {
byte[] hash = VerityUtils.getFsverityRootHash(filePath);
if (hash != null) {
return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, hash);
byte[] verityHash = VerityUtils.getFsverityRootHash(filePath);
if (verityHash != null) {
return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, verityHash);
}
}
// v4 next
try {
ApkSignatureSchemeV4Verifier.VerifiedSigner signer =
ApkSignatureSchemeV4Verifier.extractCertificates(filePath);
byte[] hash = signer.contentDigests.getOrDefault(CONTENT_DIGEST_VERITY_CHUNKED_SHA256,
null);
if (hash != null) {
return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256, hash);
byte[] rootHash = signer.contentDigests.getOrDefault(
CONTENT_DIGEST_VERITY_CHUNKED_SHA256, null);
if (rootHash != null) {
return new ApkChecksum(split, TYPE_WHOLE_MERKLE_ROOT_4K_SHA256,
verityHashForFile(new File(filePath), rootHash));
}
} catch (SignatureNotFoundException e) {
// Nothing
@@ -671,6 +673,41 @@ public class ApkChecksums {
return null;
}
/**
* Returns fs-verity digest as described in
* https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#fs-verity-descriptor
* @param file the Merkle tree is built over
* @param rootHash Merkle tree root hash
*/
static byte[] verityHashForFile(File file, byte[] rootHash) {
try {
ByteBuffer buffer = ByteBuffer.allocate(256); // sizeof(fsverity_descriptor)
buffer.order(ByteOrder.LITTLE_ENDIAN);
buffer.put((byte) 1); // __u8 version, must be 1
buffer.put((byte) 1); // __u8 hash_algorithm, FS_VERITY_HASH_ALG_SHA256
buffer.put((byte) 12); // __u8, FS_VERITY_LOG_BLOCKSIZE
buffer.put((byte) 0); // __u8, size of salt in bytes; 0 if none
buffer.putInt(0); // __le32 __reserved_0x04, must be 0
buffer.putLong(file.length()); // __le64 data_size
buffer.put(rootHash); // root_hash, first 32 bytes
final int padding = 32 + 32 + 144; // root_hash, last 32 bytes, we are using sha256.
// salt, 32 bytes
// reserved, 144 bytes
for (int i = 0; i < padding; ++i) {
buffer.put((byte) 0);
}
buffer.flip();
final MessageDigest md = MessageDigest.getInstance(ALGO_SHA256);
md.update(buffer);
return md.digest();
} catch (NoSuchAlgorithmException e) {
Slog.e(TAG, "Device does not support MessageDigest algorithm", e);
return null;
}
}
private static Map<Integer, ApkChecksum> extractHashFromV2V3Signature(
String split, String filePath, int types) {
Map<Integer, byte[]> contentDigests = null;

View File

@@ -1069,7 +1069,7 @@ public class PackageManagerServiceUtils {
if (ArrayUtils.isEmpty(hashInfo.rawRootHash)) {
throw new IOException("Root has not present");
}
return hashInfo.rawRootHash;
return ApkChecksums.verityHashForFile(new File(filename), hashInfo.rawRootHash);
} catch (IOException ignore) {
Slog.e(TAG, "ERROR: could not load root hash from incremental install");
}