"Fossies" - the Fresh Open Source Software Archive

Member "cryptsetup-2.4.3/lib/utils_wipe.c" (13 Jan 2022, 7191 Bytes) of package /linux/misc/cryptsetup-2.4.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "utils_wipe.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 2.3.6_vs_2.4.0.

    1 /*
    2  * utils_wipe - wipe a device
    3  *
    4  * Copyright (C) 2004-2007 Clemens Fruhwirth <clemens@endorphin.org>
    5  * Copyright (C) 2009-2021 Red Hat, Inc. All rights reserved.
    6  * Copyright (C) 2009-2021 Milan Broz
    7  *
    8  * This program is free software; you can redistribute it and/or
    9  * modify it under the terms of the GNU General Public License
   10  * as published by the Free Software Foundation; either version 2
   11  * of the License, or (at your option) any later version.
   12  *
   13  * This program is distributed in the hope that it will be useful,
   14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  * GNU General Public License for more details.
   17  *
   18  * You should have received a copy of the GNU General Public License
   19  * along with this program; if not, write to the Free Software
   20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   21  */
   22 
   23 #include <stdlib.h>
   24 #include <errno.h>
   25 #include "internal.h"
   26 
   27 /*
   28  * Wipe using Peter Gutmann method described in
   29  * https://www.cs.auckland.ac.nz/~pgut001/pubs/secure_del.html
   30  * Note: used only for rotational device (and even there it is not needed today...)
   31  */
   32 static void wipeSpecial(char *buffer, size_t buffer_size, unsigned int turn)
   33 {
   34     unsigned int i;
   35 
   36     unsigned char write_modes[][3] = {
   37         {"\x55\x55\x55"}, {"\xaa\xaa\xaa"}, {"\x92\x49\x24"},
   38         {"\x49\x24\x92"}, {"\x24\x92\x49"}, {"\x00\x00\x00"},
   39         {"\x11\x11\x11"}, {"\x22\x22\x22"}, {"\x33\x33\x33"},
   40         {"\x44\x44\x44"}, {"\x55\x55\x55"}, {"\x66\x66\x66"},
   41         {"\x77\x77\x77"}, {"\x88\x88\x88"}, {"\x99\x99\x99"},
   42         {"\xaa\xaa\xaa"}, {"\xbb\xbb\xbb"}, {"\xcc\xcc\xcc"},
   43         {"\xdd\xdd\xdd"}, {"\xee\xee\xee"}, {"\xff\xff\xff"},
   44         {"\x92\x49\x24"}, {"\x49\x24\x92"}, {"\x24\x92\x49"},
   45         {"\x6d\xb6\xdb"}, {"\xb6\xdb\x6d"}, {"\xdb\x6d\xb6"}
   46     };
   47 
   48     for (i = 0; i < buffer_size / 3; ++i) {
   49         memcpy(buffer, write_modes[turn], 3);
   50         buffer += 3;
   51     }
   52 }
   53 
   54 static int crypt_wipe_special(struct crypt_device *cd, int fd, size_t bsize,
   55                   size_t alignment, char *buffer,
   56                   uint64_t offset, size_t size)
   57 {
   58     int r = 0;
   59     unsigned int i;
   60     ssize_t written;
   61 
   62     for (i = 0; i < 39; ++i) {
   63         if (i <  5) {
   64             r = crypt_random_get(cd, buffer, size, CRYPT_RND_NORMAL);
   65         } else if (i >=  5 && i < 32) {
   66             wipeSpecial(buffer, size, i - 5);
   67             r = 0;
   68         } else if (i >= 32 && i < 38) {
   69             r = crypt_random_get(cd, buffer, size, CRYPT_RND_NORMAL);
   70         } else if (i >= 38 && i < 39) {
   71             memset(buffer, 0xFF, size);
   72             r = 0;
   73         }
   74         if (r < 0)
   75             return -EIO;
   76 
   77         written = write_lseek_blockwise(fd, bsize, alignment,
   78                         buffer, size, offset);
   79         if (written < 0 || written != (ssize_t)size)
   80             return -EIO;
   81     }
   82 
   83     /* Rewrite it finally with random */
   84     if (crypt_random_get(cd, buffer, size, CRYPT_RND_NORMAL) < 0)
   85         return -EIO;
   86 
   87     written = write_lseek_blockwise(fd, bsize, alignment, buffer, size, offset);
   88     if (written < 0 || written != (ssize_t)size)
   89         return -EIO;
   90 
   91     return 0;
   92 }
   93 
   94 static int wipe_block(struct crypt_device *cd, int devfd, crypt_wipe_pattern pattern,
   95               char *sf, size_t device_block_size, size_t alignment,
   96               size_t wipe_block_size, uint64_t offset, bool *need_block_init)
   97 {
   98     int r;
   99 
  100     if (pattern == CRYPT_WIPE_SPECIAL)
  101         return crypt_wipe_special(cd, devfd, device_block_size, alignment,
  102                       sf, offset, wipe_block_size);
  103 
  104     if (*need_block_init) {
  105         if (pattern == CRYPT_WIPE_ZERO) {
  106             memset(sf, 0, wipe_block_size);
  107             *need_block_init = false;
  108             r = 0;
  109         } else if (pattern == CRYPT_WIPE_RANDOM) {
  110             r = crypt_random_get(cd, sf, wipe_block_size,
  111                          CRYPT_RND_NORMAL) ? -EIO : 0;
  112             *need_block_init = true;
  113         } else if (pattern == CRYPT_WIPE_ENCRYPTED_ZERO) {
  114             // FIXME
  115             r = crypt_random_get(cd, sf, wipe_block_size,
  116                          CRYPT_RND_NORMAL) ? -EIO : 0;
  117             *need_block_init = true;
  118         } else
  119             r = -EINVAL;
  120 
  121         if (r)
  122             return r;
  123     }
  124 
  125     if (write_blockwise(devfd, device_block_size, alignment, sf,
  126                 wipe_block_size) == (ssize_t)wipe_block_size)
  127         return 0;
  128 
  129     return -EIO;
  130 }
  131 
  132 int crypt_wipe_device(struct crypt_device *cd,
  133     struct device *device,
  134     crypt_wipe_pattern pattern,
  135     uint64_t offset,
  136     uint64_t length,
  137     size_t wipe_block_size,
  138     int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
  139     void *usrptr)
  140 {
  141     int r, devfd;
  142     size_t bsize, alignment;
  143     char *sf = NULL;
  144     uint64_t dev_size;
  145     bool need_block_init = true;
  146 
  147     /* Note: LUKS1 calls it with wipe_block not aligned to multiple of bsize */
  148     bsize = device_block_size(cd, device);
  149     alignment = device_alignment(device);
  150     if (!bsize || !alignment || !wipe_block_size)
  151         return -EINVAL;
  152 
  153     /* if wipe_block_size < bsize, then a wipe is highly ineffective */
  154 
  155     /* Everything must be aligned to SECTOR_SIZE */
  156     if (MISALIGNED_512(offset) || MISALIGNED_512(length) || MISALIGNED_512(wipe_block_size))
  157         return -EINVAL;
  158 
  159     if (device_is_locked(device))
  160         devfd = device_open_locked(cd, device, O_RDWR);
  161     else
  162         devfd = device_open(cd, device, O_RDWR);
  163     if (devfd < 0)
  164         return errno ? -errno : -EINVAL;
  165 
  166     if (length)
  167         dev_size = offset + length;
  168     else {
  169         r = device_size(device, &dev_size);
  170         if (r)
  171             goto out;
  172 
  173         if (dev_size <= offset) {
  174             r = -EINVAL;
  175             goto out;
  176         }
  177     }
  178 
  179     r = posix_memalign((void **)&sf, alignment, wipe_block_size);
  180     if (r)
  181         goto out;
  182 
  183     if (lseek64(devfd, offset, SEEK_SET) < 0) {
  184         log_err(cd, _("Cannot seek to device offset."));
  185         r = -EINVAL;
  186         goto out;
  187     }
  188 
  189     if (progress && progress(dev_size, offset, usrptr)) {
  190         r = -EINVAL; /* No change yet, treat this as a parameter error */
  191         goto out;
  192     }
  193 
  194     if (pattern == CRYPT_WIPE_SPECIAL && !device_is_rotational(device)) {
  195         log_dbg(cd, "Non-rotational device, using random data wipe mode.");
  196         pattern = CRYPT_WIPE_RANDOM;
  197     }
  198 
  199     while (offset < dev_size) {
  200         if ((offset + wipe_block_size) > dev_size)
  201             wipe_block_size = dev_size - offset;
  202 
  203         //log_dbg("Wipe %012" PRIu64 "-%012" PRIu64 " bytes", offset, offset + wipe_block_size);
  204 
  205         r = wipe_block(cd, devfd, pattern, sf, bsize, alignment,
  206                    wipe_block_size, offset, &need_block_init);
  207         if (r) {
  208             log_err(cd,_("Device wipe error, offset %" PRIu64 "."), offset);
  209             break;
  210         }
  211 
  212         offset += wipe_block_size;
  213 
  214         if (progress && progress(dev_size, offset, usrptr)) {
  215             r = -EINTR;
  216             break;
  217         }
  218     }
  219 
  220     device_sync(cd, device);
  221 out:
  222     free(sf);
  223     return r;
  224 }
  225 
  226 int crypt_wipe(struct crypt_device *cd,
  227     const char *dev_path,
  228     crypt_wipe_pattern pattern,
  229     uint64_t offset,
  230     uint64_t length,
  231     size_t wipe_block_size,
  232     uint32_t flags,
  233     int (*progress)(uint64_t size, uint64_t offset, void *usrptr),
  234     void *usrptr)
  235 {
  236     struct device *device;
  237     int r;
  238 
  239     if (!cd)
  240         return -EINVAL;
  241 
  242     if (!dev_path)
  243         device = crypt_data_device(cd);
  244     else {
  245         r = device_alloc_no_check(&device, dev_path);
  246         if (r < 0)
  247             return r;
  248 
  249         if (flags & CRYPT_WIPE_NO_DIRECT_IO)
  250             device_disable_direct_io(device);
  251     }
  252 
  253     if (!wipe_block_size)
  254         wipe_block_size = 1024*1024;
  255 
  256     log_dbg(cd, "Wipe [%u] device %s, offset %" PRIu64 ", length %" PRIu64 ", block %zu.",
  257         (unsigned)pattern, device_path(device), offset, length, wipe_block_size);
  258 
  259     r = crypt_wipe_device(cd, device, pattern, offset, length,
  260                   wipe_block_size, progress, usrptr);
  261 
  262     if (dev_path)
  263         device_free(cd, device);
  264 
  265     return r;
  266 }