Make BUF_strndup() read-safe on arbitrary inputs
authorAlessandro Ghedini <alessandro@ghedini.me>
Wed, 16 Sep 2015 15:54:05 +0000 (17:54 +0200)
committerEmilia Kasper <emilia@openssl.org>
Tue, 22 Sep 2015 18:09:38 +0000 (20:09 +0200)
BUF_strndup was calling strlen through BUF_strlcpy, and ended up reading
past the input if the input was not a C string.

Make it explicitly part of BUF_strndup's contract to never read more
than |siz| input bytes. This augments the standard strndup contract to
be safer.

The commit also adds a check for siz overflow and some brief documentation
for BUF_strndup().

Reviewed-by: Matt Caswell <matt@openssl.org>
(cherry picked from commit 110f7b37de9feecfb64950601cc7cec77cf6130b)
(cherry picked from commit f61216ba9d17430fb5eb3e2b202a209960b9d51b)

crypto/buffer/buf_str.c
crypto/buffer/buffer.h

index fdde3d7db4ba0ced2d8665627b2309fa2c8655d1..da1fea9c6767835b46eda8ed2cbf41292760a176 100644 (file)
@@ -58,6 +58,7 @@
 
 #include <stdio.h>
 #include "cryptlib.h"
+#include <limits.h>
 #include <openssl/buffer.h>
 
 char *BUF_strdup(const char *str)
@@ -74,12 +75,18 @@ char *BUF_strndup(const char *str, size_t siz)
     if (str == NULL)
         return (NULL);
 
+    if (siz >= INT_MAX)
+        return (NULL);
+
     ret = OPENSSL_malloc(siz + 1);
     if (ret == NULL) {
         BUFerr(BUF_F_BUF_STRNDUP, ERR_R_MALLOC_FAILURE);
         return (NULL);
     }
-    BUF_strlcpy(ret, str, siz + 1);
+
+    memcpy(ret, str, siz);
+    ret[siz] = '\0';
+
     return (ret);
 }
 
index 632df93c657ca7abf24fe941a0f288d3e4baf61b..0958b454beef98b0c0ada276048785388320b8ef 100644 (file)
@@ -85,7 +85,13 @@ void BUF_MEM_free(BUF_MEM *a);
 int BUF_MEM_grow(BUF_MEM *str, size_t len);
 int BUF_MEM_grow_clean(BUF_MEM *str, size_t len);
 char *BUF_strdup(const char *str);
+
+/*
+ * Returns a pointer to a new string which is a duplicate of the string |str|,
+ * but guarantees to never read past the first |siz| bytes of |str|.
+ */
 char *BUF_strndup(const char *str, size_t siz);
+
 void *BUF_memdup(const void *data, size_t siz);
 void BUF_reverse(unsigned char *out, const unsigned char *in, size_t siz);