krb5 commit: Implement k5_buf_init_dynamic_zap

Greg Hudson <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.cvs
Message-ID <[email protected]>
https://github.com/krb5/krb5/commit/8ee8246c14702dc03b02e31b9fb5b7c2bb674bfb
commit 8ee8246c14702dc03b02e31b9fb5b7c2bb674bfb
Author: Greg Hudson <[email protected]>
Date:   Mon Mar 26 11:12:39 2018 -0400

    Implement k5_buf_init_dynamic_zap
    
    Add a variant of dynamic k5buf objects which zeroes memory when
    reallocating or freeing the buffer.

 src/include/k5-buf.h                          |    6 +++-
 src/util/support/k5buf.c                      |   41 ++++++++++++++++++++-----
 src/util/support/libkrb5support-fixed.exports |    1 +
 3 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/src/include/k5-buf.h b/src/include/k5-buf.h
index 1223916..48e2a7d 100644
--- a/src/include/k5-buf.h
+++ b/src/include/k5-buf.h
@@ -45,7 +45,7 @@
  */
 
 /* Buffer type values */
-enum k5buftype { K5BUF_ERROR, K5BUF_FIXED, K5BUF_DYNAMIC };
+enum k5buftype { K5BUF_ERROR, K5BUF_FIXED, K5BUF_DYNAMIC, K5BUF_DYNAMIC_ZAP };
 
 struct k5buf {
     enum k5buftype buftype;
@@ -63,6 +63,10 @@ void k5_buf_init_fixed(struct k5buf *buf, char *data, size_t space);
 /* Initialize a k5buf using an internally allocated dynamic buffer. */
 void k5_buf_init_dynamic(struct k5buf *buf);
 
+/* Initialize a k5buf using an internally allocated dynamic buffer, zeroing
+ * memory when reallocating or freeing. */
+void k5_buf_init_dynamic_zap(struct k5buf *buf);
+
 /* Add a C string to BUF. */
 void k5_buf_add(struct k5buf *buf, const char *data);
 
diff --git a/src/util/support/k5buf.c b/src/util/support/k5buf.c
index 35978f2..b2b5e5b 100644
--- a/src/util/support/k5buf.c
+++ b/src/util/support/k5buf.c
@@ -37,7 +37,7 @@
 /*
  * Structure invariants:
  *
- * buftype is K5BUF_FIXED, K5BUF_DYNAMIC, or K5BUF_ERROR
+ * buftype is K5BUF_FIXED, K5BUF_DYNAMIC, K5BUF_DYNAMIC_ZAP, or K5BUF_ERROR
  * if buftype is K5BUF_ERROR, the other fields are NULL or 0
  * if buftype is not K5BUF_ERROR:
  *   space > 0
@@ -77,22 +77,35 @@ ensure_space(struct k5buf *buf, size_t len)
         return 1;
     if (buf->buftype == K5BUF_FIXED) /* Can't resize a fixed buffer. */
         goto error_exit;
-    assert(buf->buftype == K5BUF_DYNAMIC);
+    assert(buf->buftype == K5BUF_DYNAMIC || buf->buftype == K5BUF_DYNAMIC_ZAP);
     new_space = buf->space * 2;
     while (new_space - buf->len - 1 < len) {
         if (new_space > SIZE_MAX / 2)
             goto error_exit;
         new_space *= 2;
     }
-    new_data = realloc(buf->data, new_space);
-    if (new_data == NULL)
-        goto error_exit;
+    if (buf->buftype == K5BUF_DYNAMIC_ZAP) {
+        /* realloc() could leave behind a partial copy of sensitive data. */
+        new_data = malloc(new_space);
+        if (new_data == NULL)
+            goto error_exit;
+        memcpy(new_data, buf->data, buf->len);
+        new_data[buf->len] = '\0';
+        zap(buf->data, buf->len);
+        free(buf->data);
+    } else {
+        new_data = realloc(buf->data, new_space);
+        if (new_data == NULL)
+            goto error_exit;
+    }
     buf->data = new_data;
     buf->space = new_space;
     return 1;
 
 error_exit:
-    if (buf->buftype == K5BUF_DYNAMIC)
+    if (buf->buftype == K5BUF_DYNAMIC_ZAP)
+        zap(buf->data, buf->len);
+    if (buf->buftype == K5BUF_DYNAMIC_ZAP || buf->buftype == K5BUF_DYNAMIC)
         free(buf->data);
     set_error(buf);
     return 0;
@@ -124,6 +137,14 @@ k5_buf_init_dynamic(struct k5buf *buf)
 }
 
 void
+k5_buf_init_dynamic_zap(struct k5buf *buf)
+{
+    k5_buf_init_dynamic(buf);
+    if (buf->buftype == K5BUF_DYNAMIC)
+        buf->buftype = K5BUF_DYNAMIC_ZAP;
+}
+
+void
 k5_buf_add(struct k5buf *buf, const char *data)
 {
     k5_buf_add_len(buf, data, strlen(data));
@@ -163,7 +184,7 @@ k5_buf_add_vfmt(struct k5buf *buf, const char *fmt, va_list ap)
     }
 
     /* Optimistically format the data directly into the dynamic buffer. */
-    assert(buf->buftype == K5BUF_DYNAMIC);
+    assert(buf->buftype == K5BUF_DYNAMIC || buf->buftype == K5BUF_DYNAMIC_ZAP);
     va_copy(apcopy, ap);
     r = vsnprintf(endptr(buf), remaining, fmt, apcopy);
     va_end(apcopy);
@@ -197,6 +218,8 @@ k5_buf_add_vfmt(struct k5buf *buf, const char *fmt, va_list ap)
         memcpy(endptr(buf), tmp, r + 1);
         buf->len += r;
     }
+    if (buf->buftype == K5BUF_DYNAMIC_ZAP)
+        zap(tmp, strlen(tmp));
     free(tmp);
 }
 
@@ -241,7 +264,9 @@ k5_buf_free(struct k5buf *buf)
 {
     if (buf->buftype == K5BUF_ERROR)
         return;
-    assert(buf->buftype == K5BUF_DYNAMIC);
+    assert(buf->buftype == K5BUF_DYNAMIC || buf->buftype == K5BUF_DYNAMIC_ZAP);
+    if (buf->buftype == K5BUF_DYNAMIC_ZAP)
+        zap(buf->data, buf->len);
     free(buf->data);
     set_error(buf);
 }
diff --git a/src/util/support/libkrb5support-fixed.exports b/src/util/support/libkrb5support-fixed.exports
index cb9bf08..a5e2ade 100644
--- a/src/util/support/libkrb5support-fixed.exports
+++ b/src/util/support/libkrb5support-fixed.exports
@@ -3,6 +3,7 @@ k5_base64_encode
 k5_bcmp
 k5_buf_init_fixed
 k5_buf_init_dynamic
+k5_buf_init_dynamic_zap
 k5_buf_add
 k5_buf_add_len
 k5_buf_add_fmt
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.