From: Daiki Ueno <ueno@gnu.org>
Date: Tue, 26 May 2020 08:22:37 +0000 (+0200)
Subject: read-file: add RF_SENSITIVE flag
X-Git-Tag: v1.0~4061
X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=a2080f6506701d8d9ca5111d628607a6a8013f61;p=gnulib.git

read-file: add RF_SENSITIVE flag

* lib/read-file.h (RF_SENSITIVE): New define.
* lib/read-file.c (fread_file, read_file): Take into account of
RF_SENSITIVE flag.
* modules/read-file (Depends-on): Add explicit_bzero.
This adds an alternative behavior of those functions to explicitly
clear the internal memory block when it becomes unused.  This is
useful for reading sensitive information from a file.
---

diff --git a/ChangeLog b/ChangeLog
index 291fd0788b..4b51128a21 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2020-05-27  Daiki Ueno  <ueno@gnu.org>
+
+	read-file: add RF_SENSITIVE flag
+	* lib/read-file.h (RF_SENSITIVE): New define.
+	* lib/read-file.c (fread_file, read_file): Take into account of
+	RF_SENSITIVE flag.
+	* modules/read-file (Depends-on): Add explicit_bzero.
+	This adds an alternative behavior of those functions to explicitly
+	clear the internal memory block when it becomes unused.  This is
+	useful for reading sensitive information from a file.
+
 2020-05-27  Daiki Ueno  <ueno@gnu.org>
 
 	read-file: add flags to modify reading behavior
diff --git a/lib/read-file.c b/lib/read-file.c
index 904f1c9018..36780cc157 100644
--- a/lib/read-file.c
+++ b/lib/read-file.c
@@ -31,6 +31,9 @@
 /* Get malloc, realloc, free. */
 #include <stdlib.h>
 
+/* Get explicit_bzero, memcpy. */
+#include <string.h>
+
 /* Get errno. */
 #include <errno.h>
 
@@ -38,9 +41,12 @@
    and set *LENGTH to the length of the string.  The string is
    zero-terminated, but the terminating zero byte is not counted in
    *LENGTH.  On errors, *LENGTH is undefined, errno preserves the
-   values set by system functions (if any), and NULL is returned.  */
+   values set by system functions (if any), and NULL is returned.
+
+   If the RF_SENSITIVE flag is set in FLAGS, the memory buffer
+   internally allocated will be cleared upon failure.  */
 char *
-fread_file (FILE *stream, int flags _GL_UNUSED, size_t *length)
+fread_file (FILE *stream, int flags, size_t *length)
 {
   char *buf = NULL;
   size_t alloc = BUFSIZ;
@@ -94,9 +100,25 @@ fread_file (FILE *stream, int flags _GL_UNUSED, size_t *length)
             /* Shrink the allocated memory if possible.  */
             if (size < alloc - 1)
               {
-                char *smaller_buf = realloc (buf, size + 1);
-                if (smaller_buf != NULL)
-                  buf = smaller_buf;
+                if (flags & RF_SENSITIVE)
+                  {
+                    char *smaller_buf = malloc (size + 1);
+                    if (smaller_buf == NULL)
+                      explicit_bzero (buf + size, alloc - size);
+                    else
+                      {
+                        memcpy (smaller_buf, buf, size);
+                        explicit_bzero (buf, alloc);
+                        free (buf);
+                        buf = smaller_buf;
+                      }
+                  }
+                else
+                  {
+                    char *smaller_buf = realloc (buf, size + 1);
+                    if (smaller_buf != NULL)
+                      buf = smaller_buf;
+                  }
               }
 
             buf[size] = '\0';
@@ -106,6 +128,7 @@ fread_file (FILE *stream, int flags _GL_UNUSED, size_t *length)
 
         {
           char *new_buf;
+          size_t save_alloc = alloc;
 
           if (alloc == PTRDIFF_MAX)
             {
@@ -118,7 +141,21 @@ fread_file (FILE *stream, int flags _GL_UNUSED, size_t *length)
           else
             alloc = PTRDIFF_MAX;
 
-          if (!(new_buf = realloc (buf, alloc)))
+          if (flags & RF_SENSITIVE)
+            {
+              new_buf = malloc (alloc);
+              if (!new_buf)
+                {
+                  /* BUF should be cleared below after the loop.  */
+                  save_errno = errno;
+                  break;
+                }
+              memcpy (new_buf, buf, save_alloc);
+              explicit_bzero (buf, save_alloc);
+              free (buf);
+              buf = new_buf;
+            }
+          else if (!(new_buf = realloc (buf, alloc)))
             {
               save_errno = errno;
               break;
@@ -128,6 +165,9 @@ fread_file (FILE *stream, int flags _GL_UNUSED, size_t *length)
         }
       }
 
+    if (flags & RF_SENSITIVE)
+      explicit_bzero (buf, alloc);
+
     free (buf);
     errno = save_errno;
     return NULL;
@@ -142,7 +182,8 @@ fread_file (FILE *stream, int flags _GL_UNUSED, size_t *length)
    any), and NULL is returned.
 
    If the RF_BINARY flag is set in FLAGS, the file is opened in binary
-   mode.  */
+   mode.  If the RF_SENSITIVE flag is set in FLAGS, the memory buffer
+   internally allocated will be cleared upon failure.  */
 char *
 read_file (const char *filename, int flags, size_t *length)
 {
@@ -163,6 +204,8 @@ read_file (const char *filename, int flags, size_t *length)
       if (out)
         {
           save_errno = errno;
+          if (flags & RF_SENSITIVE)
+            explicit_bzero (out, *length);
           free (out);
         }
       errno = save_errno;
diff --git a/lib/read-file.h b/lib/read-file.h
index 7ff82ca77d..c2454ef689 100644
--- a/lib/read-file.h
+++ b/lib/read-file.h
@@ -27,6 +27,9 @@
 /* Indicate that the file is treated as binary.  */
 #define RF_BINARY 0x1
 
+/* Indicate that the file content contains sensitive information.  */
+#define RF_SENSITIVE 0x2
+
 extern char *fread_file (FILE * stream, int flags, size_t * length);
 
 extern char *read_file (const char *filename, int flags, size_t * length);
diff --git a/modules/read-file b/modules/read-file
index a6e7faf0a8..5d2be5bbf4 100644
--- a/modules/read-file
+++ b/modules/read-file
@@ -7,6 +7,7 @@ lib/read-file.c
 m4/read-file.m4
 
 Depends-on:
+explicit_bzero
 fopen-gnu
 fstat
 ftello
diff --git a/tests/test-read-file.c b/tests/test-read-file.c
index 84b9049940..b37f875b22 100644
--- a/tests/test-read-file.c
+++ b/tests/test-read-file.c
@@ -117,6 +117,8 @@ main (void)
 {
   ASSERT (!test_read_file (0));
   ASSERT (!test_read_file (RF_BINARY));
+  ASSERT (!test_read_file (RF_SENSITIVE));
+  ASSERT (!test_read_file (RF_BINARY | RF_SENSITIVE));
 
   return 0;
 }