Cherry-pick: mount-encrypted: explicitly use uint64_t for sizes

On very large HDDs, the sector count was wrapping around. Switch most
calculations to bytes using uint64_t, and use BLKGETSIZE64 for checking
the loopback device size.

BUG=chrome-os-partner:12705
TEST=parrot build, manual testing
STATUS=Fixed

Change-Id: I61fed0d498e04f0b224645883929288362e44302
Signed-off-by: Kees Cook <keescook@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/31073
Reviewed-by: Elly Jones <ellyjones@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/31155
Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org>
Reviewed-by: Gaurav Shah <gauravsh@chromium.org>
diff --git a/utility/mount-encrypted.c b/utility/mount-encrypted.c
index 26f1542..f5d79aa 100644
--- a/utility/mount-encrypted.c
+++ b/utility/mount-encrypted.c
@@ -15,6 +15,7 @@
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <grp.h>
 #include <pwd.h>
 #include <sys/ioctl.h>
@@ -53,9 +54,9 @@
 static const uint32_t kLockboxSizeV1 = 0x2c;
 static const uint32_t kLockboxSizeV2 = 0x45;
 static const uint32_t kLockboxSaltOffset = 0x5;
-static const size_t kSectorSize = 512;
-static const size_t kExt4BlockSize = 4096;
-static const size_t kExt4MinBytes = 16 * 1024 * 1024;
+static const uint64_t kSectorSize = 512;
+static const uint64_t kExt4BlockSize = 4096;
+static const uint64_t kExt4MinBytes = 16 * 1024 * 1024;
 static const char * const kStaticKeyDefault = "default unsafe static key";
 static const char * const kStaticKeyFactory = "factory unsafe static key";
 static const char * const kStaticKeyFinalizationNeeded = "needs finalization";
@@ -673,14 +674,14 @@
 	return EXIT_SUCCESS;
 }
 
-static void spawn_resizer(const char *device, size_t blocks,
-			  size_t blocks_max)
+static void spawn_resizer(const char *device, uint64_t blocks,
+			  uint64_t blocks_max)
 {
 	pid_t pid;
 
 	/* Skip resize before forking, if it's not going to happen. */
 	if (blocks >= blocks_max) {
-		INFO("Resizing skipped. blocks:%zu >= blocks_max:%zu",
+		INFO("Resizing skipped. blocks:%" PRIu64 " >= blocks_max:%" PRIu64,
 		     blocks, blocks_max);
 		return;
 	}
@@ -723,11 +724,11 @@
 	char *encryption_key = NULL;
 	int migrate_allowed = 0, migrate_needed = 0, rebuild = 0;
 	gchar *lodev = NULL;
-	size_t sectors;
+	uint64_t sectors;
 	struct bind_mount *bind;
 	int sparsefd;
 	struct statvfs stateful_statbuf;
-	size_t blocks_min, blocks_max;
+	uint64_t blocks_min, blocks_max;
 
 	/* Use the "system key" to decrypt the "encryption key" stored in
 	 * the stateful partition.
@@ -764,7 +765,7 @@
 	}
 
 	if (rebuild) {
-		off_t fs_bytes_max;
+		uint64_t fs_bytes_max;
 
 		/* Wipe out the old files, and ignore errors. */
 		unlink(key_path);
@@ -779,8 +780,8 @@
 		fs_bytes_max *= kSizePercent;
 		fs_bytes_max *= stateful_statbuf.f_frsize;
 
-		INFO("Creating sparse backing file with size %llu.",
-		     (unsigned long long)fs_bytes_max);
+		INFO("Creating sparse backing file with size %" PRIu64 ".",
+		     fs_bytes_max);
 
 		/* Create the sparse file. */
 		sparsefd = sparse_create(block_path, fs_bytes_max);
@@ -805,7 +806,7 @@
 	}
 
 	/* Get size as seen by block device. */
-	sectors = get_sectors(lodev);
+	sectors = blk_size(lodev) / kSectorSize;
 	if (!sectors) {
 		ERROR("Failed to read device size");
 		goto lo_cleanup;
@@ -848,8 +849,8 @@
 	blocks_max = sectors / (kExt4BlockSize / kSectorSize);
 	blocks_min = kExt4MinBytes / kExt4BlockSize;
 	if (migrate_needed && migrate_allowed) {
-		off_t fs_bytes_min;
-		size_t calc_blocks_min;
+		uint64_t fs_bytes_min;
+		uint64_t calc_blocks_min;
 		/* When doing a migration, the new filesystem must be
 		 * large enough to hold what we're going to migrate.
 		 * Instead of walking the bind mount sources, which would
@@ -863,8 +864,7 @@
 		fs_bytes_min = stateful_statbuf.f_blocks -
 			       stateful_statbuf.f_bfree;
 		fs_bytes_min *= stateful_statbuf.f_frsize;
-		DEBUG("Stateful bytes used: %llu",
-			(unsigned long long)fs_bytes_min);
+		DEBUG("Stateful bytes used: %" PRIu64 "", fs_bytes_min);
 		fs_bytes_min *= kMigrationSizeMultiplier;
 
 		/* Minimum blocks needed for that many bytes. */
@@ -876,15 +876,15 @@
 		else if (calc_blocks_min < blocks_min)
 			calc_blocks_min = blocks_min;
 
-		DEBUG("Maximum fs blocks: %zu", blocks_max);
-		DEBUG("Minimum fs blocks: %zu", blocks_min);
-		DEBUG("Migration blocks chosen: %zu", calc_blocks_min);
+		DEBUG("Maximum fs blocks: %" PRIu64 "", blocks_max);
+		DEBUG("Minimum fs blocks: %" PRIu64 "", blocks_min);
+		DEBUG("Migration blocks chosen: %" PRIu64 "", calc_blocks_min);
 		blocks_min = calc_blocks_min;
 	}
 
 	if (rebuild) {
 		INFO("Building filesystem on %s "
-			"(blocksize:%zu, min:%zu, max:%zu).",
+			"(blocksize:%" PRIu64 ", min:%" PRIu64 ", max:%" PRIu64 ").",
 			dmcrypt_dev, kExt4BlockSize, blocks_min, blocks_max);
 		if (!filesystem_build(dmcrypt_dev, kExt4BlockSize,
 					blocks_min, blocks_max))
diff --git a/utility/mount-helpers.c b/utility/mount-helpers.c
index 7647ffa..29db21c 100644
--- a/utility/mount-helpers.c
+++ b/utility/mount-helpers.c
@@ -15,6 +15,7 @@
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <inttypes.h>
 #include <math.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
@@ -38,10 +39,10 @@
 static const int kLoopMajor = 7;
 static const int kLoopMax = 8;
 static const unsigned int kResizeStepSeconds = 2;
-static const size_t kResizeBlocks = 32768 * 10;
-static const size_t kBlocksPerGroup = 32768;
-static const size_t kInodeRatioDefault = 16384;
-static const size_t kInodeRatioMinimum = 2048;
+static const uint64_t kResizeBlocks = 32768 * 10;
+static const uint64_t kBlocksPerGroup = 32768;
+static const uint64_t kInodeRatioDefault = 16384;
+static const uint64_t kInodeRatioMinimum = 2048;
 static const gchar * const kExt4ExtendedOptions = "discard,lazy_itable_init";
 
 int remove_tree(const char *tree)
@@ -54,20 +55,20 @@
 	return runcmd(rm, NULL);
 }
 
-size_t get_sectors(const char *device)
+uint64_t blk_size(const char *device)
 {
-	size_t sectors;
+	uint64_t bytes;
 	int fd;
 	if ((fd = open(device, O_RDONLY | O_NOFOLLOW)) < 0) {
 		PERROR("open(%s)", device);
 		return 0;
 	}
-	if (ioctl(fd, BLKGETSIZE, &sectors)) {
-		PERROR("ioctl(%s, BLKGETSIZE)", device);
+	if (ioctl(fd, BLKGETSIZE64, &bytes)) {
+		PERROR("ioctl(%s, BLKGETSIZE64)", device);
 		return 0;
 	}
 	close(fd);
-	return sectors;
+	return bytes;
 }
 
 int runcmd(const gchar *argv[], gchar **output)
@@ -342,11 +343,11 @@
 	return 0;
 }
 
-int dm_setup(size_t sectors, const gchar *encryption_key, const char *name,
+int dm_setup(uint64_t sectors, const gchar *encryption_key, const char *name,
 		const gchar *device, const char *path, int discard)
 {
 	/* Mount loopback device with dm-crypt using the encryption key. */
-	gchar *table = g_strdup_printf("0 %zu crypt " \
+	gchar *table = g_strdup_printf("0 %" PRIu64 " crypt " \
 				       "aes-cbc-essiv:sha256 %s " \
 				       "0 %s 0%s",
 				       sectors,
@@ -425,7 +426,7 @@
 	return key;
 }
 
-int sparse_create(const char *path, size_t size)
+int sparse_create(const char *path, uint64_t bytes)
 {
 	int sparsefd;
 
@@ -434,7 +435,7 @@
 	if (sparsefd < 0)
 		goto out;
 
-	if (ftruncate(sparsefd, size)) {
+	if (ftruncate(sparsefd, bytes)) {
 		int saved_errno = errno;
 
 		close(sparsefd);
@@ -460,8 +461,9 @@
  *      ------------------------------------------------------------------
  *      ceil(size_max / inode-ratio_max) * ceil(blocks_mkfs / group-ratio)
  */
-static size_t get_inode_ratio(size_t block_bytes_in, size_t blocks_mkfs_in,
-				size_t blocks_max_in)
+static uint64_t get_inode_ratio(uint64_t block_bytes_in,
+				uint64_t blocks_mkfs_in,
+				uint64_t blocks_max_in)
 {
 	double block_bytes = (double)block_bytes_in;
 	double blocks_mkfs = (double)blocks_mkfs_in;
@@ -491,7 +493,7 @@
 	if (inode_ratio_mkfs < kInodeRatioMinimum)
 		goto failure;
 
-	return (size_t)inode_ratio_mkfs;
+	return (uint64_t)inode_ratio_mkfs;
 
 failure:
 	return kInodeRatioDefault;
@@ -505,20 +507,20 @@
  *
  * Returns 1 on success, 0 on failure.
  */
-int filesystem_build(const char *device, size_t block_bytes, size_t blocks_min,
-			size_t blocks_max)
+int filesystem_build(const char *device, uint64_t block_bytes,
+		     uint64_t blocks_min, uint64_t blocks_max)
 {
 	int rc = 0;
-	size_t inode_ratio;
+	uint64_t inode_ratio;
 
-	gchar *blocksize = g_strdup_printf("%zu", block_bytes);
+	gchar *blocksize = g_strdup_printf("%" PRIu64, block_bytes);
 	if (!blocksize) {
 		PERROR("g_strdup_printf");
 		goto out;
 	}
 
 	gchar *blocks_str;
-	blocks_str = g_strdup_printf("%zu", blocks_min);
+	blocks_str = g_strdup_printf("%" PRIu64, blocks_min);
 	if (!blocks_str) {
 		PERROR("g_strdup_printf");
 		goto free_blocksize;
@@ -526,7 +528,7 @@
 
 	gchar *extended;
 	if (blocks_min < blocks_max) {
-		extended = g_strdup_printf("%s,resize=%zu",
+		extended = g_strdup_printf("%s,resize=%" PRIu64,
 			kExt4ExtendedOptions, blocks_max);
 	} else {
 		extended = g_strdup_printf("%s", kExt4ExtendedOptions);
@@ -537,7 +539,7 @@
 	}
 
 	inode_ratio = get_inode_ratio(block_bytes, blocks_min, blocks_max);
-	gchar *inode_ratio_str = g_strdup_printf("%zu", inode_ratio);
+	gchar *inode_ratio_str = g_strdup_printf("%" PRIu64, inode_ratio);
 	if (!inode_ratio_str) {
 		PERROR("g_strdup_printf");
 		goto free_extended;
@@ -582,11 +584,11 @@
 }
 
 /* Spawns a filesystem resizing process. */
-int filesystem_resize(const char *device, size_t blocks, size_t blocks_max)
+int filesystem_resize(const char *device, uint64_t blocks, uint64_t blocks_max)
 {
 	/* Ignore resizing if we know the filesystem was built to max size. */
 	if (blocks >= blocks_max) {
-		INFO("Resizing aborted. blocks:%zu >= blocks_max:%zu",
+		INFO("Resizing aborted. blocks:%" PRIu64 " >= blocks_max:%" PRIu64,
 		     blocks, blocks_max);
 		return 1;
 	}
@@ -609,7 +611,7 @@
 		if (blocks > blocks_max)
 			blocks = blocks_max;
 
-		blocks_str = g_strdup_printf("%zu", blocks);
+		blocks_str = g_strdup_printf("%" PRIu64, blocks);
 		if (!blocks_str) {
 			PERROR("g_strdup_printf");
 			return 0;
@@ -623,7 +625,7 @@
 			NULL
 		};
 
-		INFO("Resizing filesystem on %s to %zu.", device, blocks);
+		INFO("Resizing filesystem on %s to %" PRIu64 ".", device, blocks);
 		if (runcmd(resize, NULL)) {
 			ERROR("resize2fs failed");
 			return 0;
diff --git a/utility/mount-helpers.h b/utility/mount-helpers.h
index c5554b3..d2aa179 100644
--- a/utility/mount-helpers.h
+++ b/utility/mount-helpers.h
@@ -8,7 +8,7 @@
 #define _MOUNT_HELPERS_H_
 
 /* General utility functions. */
-size_t get_sectors(const char *device);
+uint64_t blk_size(const char *device);
 int remove_tree(const char *tree);
 int runcmd(const gchar *argv[], gchar **output);
 int same_vfs(const char *mnt_a, const char *mnt_b);
@@ -22,18 +22,18 @@
 int loop_detach_name(const char *name);
 
 /* Encrypted device mapper setup/teardown. */
-int dm_setup(size_t sectors, const gchar *encryption_key, const char *name,
+int dm_setup(uint64_t bytes, const gchar *encryption_key, const char *name,
 		const gchar *device, const char *path, int discard);
 int dm_teardown(const gchar *device);
 char *dm_get_key(const gchar *device);
 
 /* Sparse file creation. */
-int sparse_create(const char *path, size_t size);
+int sparse_create(const char *path, uint64_t bytes);
 
 /* Filesystem creation. */
-int filesystem_build(const char *device, size_t block_bytes, size_t blocks_min,
-			size_t blocks_max);
-int filesystem_resize(const char *device, size_t blocks, size_t blocks_max);
+int filesystem_build(const char *device, uint64_t block_bytes,
+			uint64_t blocks_min, uint64_t blocks_max);
+int filesystem_resize(const char *device, uint64_t blocks, uint64_t blocks_max);
 
 /* Encrypted keyfile handling. */
 char *keyfile_read(const char *keyfile, uint8_t *system_key);