Home | History | Annotate | Download | only in vold
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <memory>
     18 #include <string>
     19 #include <vector>
     20 
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <errno.h>
     24 #include <sys/types.h>
     25 #include <sys/stat.h>
     26 #include <fcntl.h>
     27 #include <linux/fs.h>
     28 #include <linux/fiemap.h>
     29 #include <mntent.h>
     30 
     31 #include <android-base/logging.h>
     32 #include <android-base/unique_fd.h>
     33 
     34 #include "FileDeviceUtils.h"
     35 
     36 namespace {
     37 
     38 struct Options {
     39     std::vector<std::string> targets;
     40     bool unlink{true};
     41 };
     42 
     43 constexpr uint32_t max_extents = 32;
     44 
     45 bool read_command_line(int argc, const char * const argv[], Options &options);
     46 void usage(const char *progname);
     47 bool secdiscard_path(const std::string &path);
     48 bool check_fiemap(const struct fiemap &fiemap, const std::string &path);
     49 bool overwrite_with_zeros(int fd, off64_t start, off64_t length);
     50 
     51 }
     52 
     53 int main(int argc, const char * const argv[]) {
     54     android::base::InitLogging(const_cast<char **>(argv));
     55     Options options;
     56     if (!read_command_line(argc, argv, options)) {
     57         usage(argv[0]);
     58         return -1;
     59     }
     60     for (auto const &target: options.targets) {
     61         LOG(DEBUG) << "Securely discarding '" << target << "' unlink=" << options.unlink;
     62         if (!secdiscard_path(target)) {
     63             LOG(ERROR) << "Secure discard failed for: " << target;
     64         }
     65         if (options.unlink) {
     66             if (unlink(target.c_str()) != 0 && errno != ENOENT) {
     67                 PLOG(ERROR) << "Unable to unlink: " << target;
     68             }
     69         }
     70         LOG(DEBUG) << "Discarded: " << target;
     71     }
     72     return 0;
     73 }
     74 
     75 namespace {
     76 
     77 bool read_command_line(int argc, const char * const argv[], Options &options) {
     78     for (int i = 1; i < argc; i++) {
     79         if (!strcmp("--no-unlink", argv[i])) {
     80             options.unlink = false;
     81         } else if (!strcmp("--", argv[i])) {
     82             for (int j = i+1; j < argc; j++) {
     83                 if (argv[j][0] != '/') return false; // Must be absolute path
     84                 options.targets.emplace_back(argv[j]);
     85             }
     86             return options.targets.size() > 0;
     87         } else {
     88             return false; // Unknown option
     89         }
     90     }
     91     return false; // "--" not found
     92 }
     93 
     94 void usage(const char *progname) {
     95     fprintf(stderr, "Usage: %s [--no-unlink] -- <absolute path> ...\n", progname);
     96 }
     97 
     98 // BLKSECDISCARD all content in "path", if it's small enough.
     99 bool secdiscard_path(const std::string &path) {
    100     auto fiemap = android::vold::PathFiemap(path, max_extents);
    101     if (!fiemap || !check_fiemap(*fiemap, path)) {
    102         return false;
    103     }
    104     auto block_device = android::vold::BlockDeviceForPath(path);
    105     if (block_device.empty()) {
    106         return false;
    107     }
    108     android::base::unique_fd fs_fd(TEMP_FAILURE_RETRY(open(
    109         block_device.c_str(), O_RDWR | O_LARGEFILE | O_CLOEXEC, 0)));
    110     if (fs_fd == -1) {
    111         PLOG(ERROR) << "Failed to open device " << block_device;
    112         return false;
    113     }
    114     for (uint32_t i = 0; i < fiemap->fm_mapped_extents; i++) {
    115         uint64_t range[2];
    116         range[0] = fiemap->fm_extents[i].fe_physical;
    117         range[1] = fiemap->fm_extents[i].fe_length;
    118         if (ioctl(fs_fd.get(), BLKSECDISCARD, range) == -1) {
    119             PLOG(ERROR) << "Unable to BLKSECDISCARD " << path;
    120             if (!overwrite_with_zeros(fs_fd.get(), range[0], range[1])) return false;
    121             LOG(DEBUG) << "Used zero overwrite";
    122         }
    123     }
    124     return true;
    125 }
    126 
    127 // Ensure that the FIEMAP covers the file and is OK to discard
    128 bool check_fiemap(const struct fiemap &fiemap, const std::string &path) {
    129     auto mapped = fiemap.fm_mapped_extents;
    130     if (!(fiemap.fm_extents[mapped - 1].fe_flags & FIEMAP_EXTENT_LAST)) {
    131         LOG(ERROR) << "Extent " << mapped -1 << " was not the last in " << path;
    132         return false;
    133     }
    134     for (uint32_t i = 0; i < mapped; i++) {
    135         auto flags = fiemap.fm_extents[i].fe_flags;
    136         if (flags & (FIEMAP_EXTENT_UNKNOWN | FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_NOT_ALIGNED)) {
    137             LOG(ERROR) << "Extent " << i << " has unexpected flags " << flags << ": " << path;
    138             return false;
    139         }
    140     }
    141     return true;
    142 }
    143 
    144 bool overwrite_with_zeros(int fd, off64_t start, off64_t length) {
    145     if (lseek64(fd, start, SEEK_SET) != start) {
    146         PLOG(ERROR) << "Seek failed for zero overwrite";
    147         return false;
    148     }
    149     char buf[BUFSIZ];
    150     memset(buf, 0, sizeof(buf));
    151     while (length > 0) {
    152         size_t wlen = static_cast<size_t>(std::min(static_cast<off64_t>(sizeof(buf)), length));
    153         auto written = write(fd, buf, wlen);
    154         if (written < 1) {
    155             PLOG(ERROR) << "Write of zeroes failed";
    156             return false;
    157         }
    158         length -= written;
    159     }
    160     return true;
    161 }
    162 
    163 }
    164