Integer overflow observed while formatting volume

While calculating volume size, get_block_device_size() returns
u64 value but the returned value is assigned in ssize_t variable.
This may cause integer overflow if the volume size is beyond
ssize_t limit.

Use int64_t instead of ssize_t in get_file_size() and explicitly check
for overflow to fix the issue.

Bug: 65001754
Test: mmma bootable/recovery
Change-Id: I91eb30bff0bf7dcc48678efc2f414d2b79af6d0d
diff --git a/roots.cpp b/roots.cpp
index fdcbfe8..26602a7 100644
--- a/roots.cpp
+++ b/roots.cpp
@@ -18,6 +18,7 @@
 
 #include <ctype.h>
 #include <fcntl.h>
+#include <stdint.h>
 #include <stdlib.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
@@ -178,16 +179,22 @@
   return WEXITSTATUS(status);
 }
 
-static ssize_t get_file_size(int fd, uint64_t reserve_len) {
+static int64_t get_file_size(int fd, uint64_t reserve_len) {
   struct stat buf;
   int ret = fstat(fd, &buf);
   if (ret) return 0;
 
-  ssize_t computed_size;
+  int64_t computed_size;
   if (S_ISREG(buf.st_mode)) {
     computed_size = buf.st_size - reserve_len;
   } else if (S_ISBLK(buf.st_mode)) {
-    computed_size = get_block_device_size(fd) - reserve_len;
+    uint64_t block_device_size = get_block_device_size(fd);
+    if (block_device_size < reserve_len ||
+        block_device_size > std::numeric_limits<int64_t>::max()) {
+      computed_size = 0;
+    } else {
+      computed_size = block_device_size - reserve_len;
+    }
   } else {
     computed_size = 0;
   }
@@ -231,13 +238,13 @@
     close(fd);
   }
 
-  ssize_t length = 0;
+  int64_t length = 0;
   if (v->length != 0) {
     length = v->length;
   } else if (v->key_loc != nullptr && strcmp(v->key_loc, "footer") == 0) {
     android::base::unique_fd fd(open(v->blk_device, O_RDONLY));
     if (fd == -1) {
-      PLOG(ERROR) << "get_file_size: failed to open " << v->blk_device;
+      PLOG(ERROR) << "format_volume: failed to open " << v->blk_device;
       return -1;
     }
     length = get_file_size(fd.get(), CRYPT_FOOTER_OFFSET);