Use proper path prefix macros in spec
[platform/upstream/cryptsetup.git] / lib / utils_crypt.c
index c2111c7..5cfe477 100644 (file)
@@ -3,10 +3,12 @@
  *
  * Copyright (C) 2004-2007, Clemens Fruhwirth <clemens@endorphin.org>
  * Copyright (C) 2009-2012, Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2009-2012, Milan Broz
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -79,6 +81,18 @@ int crypt_parse_name_and_mode(const char *s, char *cipher, int *key_nums,
        return -EINVAL;
 }
 
+/*
+ * Replacement for memset(s, 0, n) on stack that can be optimized out
+ * Also used in safe allocations for explicit memory wipe.
+ */
+void crypt_memzero(void *s, size_t n)
+{
+       volatile uint8_t *p = (volatile uint8_t *)s;
+
+       while(n--)
+               *p++ = 0;
+}
+
 /* safe allocations */
 void *crypt_safe_alloc(size_t size)
 {
@@ -92,7 +106,9 @@ void *crypt_safe_alloc(size_t size)
                return NULL;
 
        alloc->size = size;
+       crypt_memzero(&alloc->data, size);
 
+       /* coverity[leaked_storage] */
        return &alloc->data;
 }
 
@@ -106,7 +122,7 @@ void crypt_safe_free(void *data)
        alloc = (struct safe_allocation *)
                ((char *)data - offsetof(struct safe_allocation, data));
 
-       memset(data, 0, alloc->size);
+       crypt_memzero(data, alloc->size);
 
        alloc->size = 0x55aa55aa;
        free(alloc);
@@ -153,7 +169,7 @@ static int untimed_read(int fd, char *pass, size_t maxlen)
 static int timed_read(int fd, char *pass, size_t maxlen, long timeout)
 {
        struct timeval t;
-       fd_set fds;
+       fd_set fds = {}; /* Just to avoid scan-build false report for FD_SET */
        int failed = -1;
 
        FD_ZERO(&fds);
@@ -172,16 +188,18 @@ static int interactive_pass(const char *prompt, char *pass, size_t maxlen,
 {
        struct termios orig, tmp;
        int failed = -1;
-       int infd = STDIN_FILENO, outfd;
+       int infd, outfd;
 
        if (maxlen < 1)
-               goto out_err;
+               return failed;
 
        /* Read and write to /dev/tty if available */
-       if ((infd = outfd = open("/dev/tty", O_RDWR)) == -1) {
+       infd = open("/dev/tty", O_RDWR);
+       if (infd == -1) {
                infd = STDIN_FILENO;
                outfd = STDERR_FILENO;
-       }
+       } else
+               outfd = infd;
 
        if (tcgetattr(infd, &orig))
                goto out_err;
@@ -262,6 +280,49 @@ out_err:
 }
 
 /*
+ * A simple call to lseek(3) might not be possible for some inputs (e.g.
+ * reading from a pipe), so this function instead reads of up to BUFSIZ bytes
+ * at a time until the specified number of bytes. It returns -1 on read error
+ * or when it reaches EOF before the requested number of bytes have been
+ * discarded.
+ */
+static int keyfile_seek(int fd, size_t bytes)
+{
+       char tmp[BUFSIZ];
+       size_t next_read;
+       ssize_t bytes_r;
+       off_t r;
+
+       r = lseek(fd, bytes, SEEK_CUR);
+       if (r > 0)
+               return 0;
+       if (r < 0 && errno != ESPIPE)
+               return -1;
+
+       while (bytes > 0) {
+               /* figure out how much to read */
+               next_read = bytes > sizeof(tmp) ? sizeof(tmp) : bytes;
+
+               bytes_r = read(fd, tmp, next_read);
+               if (bytes_r < 0) {
+                       if (errno == EINTR)
+                               continue;
+
+                       /* read error */
+                       return -1;
+               }
+
+               if (bytes_r == 0)
+                       /* EOF */
+                       break;
+
+               bytes -= bytes_r;
+       }
+
+       return bytes == 0 ? 0 : -1;
+}
+
+/*
  * Note: --key-file=- is interpreted as a read from a binary file (stdin)
  * key_size_max == 0 means detect maximum according to input type (tty/file)
  * timeout and verify options only applies to tty input
@@ -274,7 +335,7 @@ int crypt_get_key(const char *prompt,
 {
        int fd, regular_file, read_stdin, char_read, unlimited_read = 0;
        int r = -EINVAL;
-       char *pass = NULL, tmp;
+       char *pass = NULL;
        size_t buflen, i, file_read_size;
        struct stat st;
 
@@ -342,11 +403,10 @@ int crypt_get_key(const char *prompt,
        }
 
        /* Discard keyfile_offset bytes on input */
-       for(i = 0; i < keyfile_offset; i++)
-               if (read(fd, &tmp, 1) != 1) {
-                       log_err(cd, _("Cannot seek to requested keyfile offset.\n"));
-                       goto out_err;
-               }
+       if (keyfile_offset && keyfile_seek(fd, keyfile_offset) < 0) {
+               log_err(cd, _("Cannot seek to requested keyfile offset.\n"));
+               goto out_err;
+       }
 
        for(i = 0; i < keyfile_size_max; i++) {
                if(i == buflen) {
@@ -467,10 +527,13 @@ int crypt_string_to_size(struct crypt_device *cd, const char *s, uint64_t *size)
                break;
        case 't':
        case 'T': mult *= mult_base;
+                /* Fall through */
        case 'g':
        case 'G': mult *= mult_base;
+                /* Fall through */
        case 'm':
        case 'M': mult *= mult_base;
+                /* Fall through */
        case 'k':
        case 'K': mult *= mult_base;
                break;