Zero out blocks if BLKSECDISCARD fails

On a device where we can't BLKSECDISCARD sectors, we "overwrite" them
with zeroes. This changes the FTL to remap those sectors to new
locations.  With this done, the old contents are accessible only given
a compromise of flash firmware or a die level attack.

Bug: 26021231
Change-Id: Ia065921389886fac1ba456c19c138187237c2561
diff --git a/secdiscard.cpp b/secdiscard.cpp
index 5c12cdd..fe51990 100644
--- a/secdiscard.cpp
+++ b/secdiscard.cpp
@@ -43,11 +43,12 @@
 
 bool read_command_line(int argc, const char * const argv[], Options &options);
 void usage(const char *progname);
-int secdiscard_path(const std::string &path);
+bool secdiscard_path(const std::string &path);
 std::unique_ptr<struct fiemap> path_fiemap(const std::string &path, uint32_t extent_count);
 bool check_fiemap(const struct fiemap &fiemap, const std::string &path);
 std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count);
 std::string block_device_for_path(const std::string &path);
+bool overwrite_with_zeros(int fd, off64_t start, off64_t length);
 
 }
 
@@ -58,9 +59,11 @@
         usage(argv[0]);
         return -1;
     }
-    for (auto target: options.targets) {
+    for (auto const &target: options.targets) {
         LOG(DEBUG) << "Securely discarding '" << target << "' unlink=" << options.unlink;
-        secdiscard_path(target);
+        if (!secdiscard_path(target)) {
+            LOG(ERROR) << "Secure discard failed for: " << target;
+        }
         if (options.unlink) {
             if (unlink(target.c_str()) != 0 && errno != ENOENT) {
                 PLOG(ERROR) << "Unable to unlink: " << target;
@@ -95,19 +98,19 @@
 }
 
 // BLKSECDISCARD all content in "path", if it's small enough.
-int secdiscard_path(const std::string &path) {
+bool secdiscard_path(const std::string &path) {
     auto fiemap = path_fiemap(path, max_extents);
     if (!fiemap || !check_fiemap(*fiemap, path)) {
-        return -1;
+        return false;
     }
     auto block_device = block_device_for_path(path);
     if (block_device.empty()) {
-        return -1;
+        return false;
     }
     AutoCloseFD fs_fd(block_device, O_RDWR | O_LARGEFILE);
     if (!fs_fd) {
         PLOG(ERROR) << "Failed to open device " << block_device;
-        return -1;
+        return false;
     }
     for (uint32_t i = 0; i < fiemap->fm_mapped_extents; i++) {
         uint64_t range[2];
@@ -115,10 +118,11 @@
         range[1] = fiemap->fm_extents[i].fe_length;
         if (ioctl(fs_fd.get(), BLKSECDISCARD, range) == -1) {
             PLOG(ERROR) << "Unable to BLKSECDISCARD " << path;
-            return -1;
+            if (!overwrite_with_zeros(fs_fd.get(), range[0], range[1])) return false;
+            LOG(DEBUG) << "Used zero overwrite";
         }
     }
-    return 0;
+    return true;
 }
 
 // Read the file's FIEMAP
@@ -206,4 +210,23 @@
     return result;
 }
 
+bool overwrite_with_zeros(int fd, off64_t start, off64_t length) {
+    if (lseek64(fd, start, SEEK_SET) != start) {
+        PLOG(ERROR) << "Seek failed for zero overwrite";
+        return false;
+    }
+    char buf[BUFSIZ];
+    memset(buf, 0, sizeof(buf));
+    while (length > 0) {
+        size_t wlen = static_cast<size_t>(std::min(static_cast<off64_t>(sizeof(buf)), length));
+        auto written = write(fd, buf, wlen);
+        if (written < 1) {
+            PLOG(ERROR) << "Write of zeroes failed";
+            return false;
+        }
+        length -= written;
+    }
+    return true;
+}
+
 }