Jelajahi Sumber

crypto/hash: avoid overwriting user supplied result pointer

If the user provides a pre-allocated buffer for the hash result,
we must use that rather than re-allocating a new buffer.

Reported-by: Dorjoy Chowdhury <dorjoychy111@gmail.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
Daniel P. Berrangé 10 bulan lalu
induk
melakukan
dde538c9a7
4 mengubah file dengan 45 tambahan dan 11 penghapusan
  1. 12 3
      crypto/hash-gcrypt.c
  2. 9 2
      crypto/hash-glib.c
  3. 13 3
      crypto/hash-gnutls.c
  4. 11 3
      crypto/hash-nettle.c

+ 12 - 3
crypto/hash-gcrypt.c

@@ -103,16 +103,25 @@ int qcrypto_gcrypt_hash_finalize(QCryptoHash *hash,
                                  size_t *result_len,
                                  size_t *result_len,
                                  Error **errp)
                                  Error **errp)
 {
 {
+    int ret;
     unsigned char *digest;
     unsigned char *digest;
     gcry_md_hd_t *ctx = hash->opaque;
     gcry_md_hd_t *ctx = hash->opaque;
 
 
-    *result_len = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[hash->alg]);
-    if (*result_len == 0) {
+    ret = gcry_md_get_algo_dlen(qcrypto_hash_alg_map[hash->alg]);
+    if (ret == 0) {
         error_setg(errp, "Unable to get hash length");
         error_setg(errp, "Unable to get hash length");
         return -1;
         return -1;
     }
     }
 
 
-    *result = g_new(uint8_t, *result_len);
+    if (*result_len == 0) {
+        *result_len = ret;
+        *result = g_new(uint8_t, *result_len);
+    } else if (*result_len != ret) {
+        error_setg(errp,
+                   "Result buffer size %zu is smaller than hash %d",
+                   *result_len, ret);
+        return -1;
+    }
 
 
     /* Digest is freed by gcry_md_close(), copy it */
     /* Digest is freed by gcry_md_close(), copy it */
     digest = gcry_md_read(*ctx, 0);
     digest = gcry_md_read(*ctx, 0);

+ 9 - 2
crypto/hash-glib.c

@@ -99,8 +99,15 @@ int qcrypto_glib_hash_finalize(QCryptoHash *hash,
         return -1;
         return -1;
     }
     }
 
 
-    *result_len = ret;
-    *result = g_new(uint8_t, *result_len);
+    if (*result_len == 0) {
+        *result_len = ret;
+        *result = g_new(uint8_t, *result_len);
+    } else if (*result_len != ret) {
+        error_setg(errp,
+                   "Result buffer size %zu is smaller than hash %d",
+                   *result_len, ret);
+        return -1;
+    }
 
 
     g_checksum_get_digest(ctx, *result, result_len);
     g_checksum_get_digest(ctx, *result, result_len);
     return 0;
     return 0;

+ 13 - 3
crypto/hash-gnutls.c

@@ -115,14 +115,24 @@ int qcrypto_gnutls_hash_finalize(QCryptoHash *hash,
                                  Error **errp)
                                  Error **errp)
 {
 {
     gnutls_hash_hd_t *ctx = hash->opaque;
     gnutls_hash_hd_t *ctx = hash->opaque;
+    int ret;
 
 
-    *result_len = gnutls_hash_get_len(qcrypto_hash_alg_map[hash->alg]);
-    if (*result_len == 0) {
+    ret = gnutls_hash_get_len(qcrypto_hash_alg_map[hash->alg]);
+    if (ret == 0) {
         error_setg(errp, "Unable to get hash length");
         error_setg(errp, "Unable to get hash length");
         return -1;
         return -1;
     }
     }
 
 
-    *result = g_new(uint8_t, *result_len);
+    if (*result_len == 0) {
+        *result_len = ret;
+        *result = g_new(uint8_t, *result_len);
+    } else if (*result_len != ret) {
+        error_setg(errp,
+                   "Result buffer size %zu is smaller than hash %d",
+                   *result_len, ret);
+        return -1;
+    }
+
     gnutls_hash_output(*ctx, *result);
     gnutls_hash_output(*ctx, *result);
     return 0;
     return 0;
 }
 }

+ 11 - 3
crypto/hash-nettle.c

@@ -150,9 +150,17 @@ int qcrypto_nettle_hash_finalize(QCryptoHash *hash,
                                  Error **errp)
                                  Error **errp)
 {
 {
     union qcrypto_hash_ctx *ctx = hash->opaque;
     union qcrypto_hash_ctx *ctx = hash->opaque;
-
-    *result_len = qcrypto_hash_alg_map[hash->alg].len;
-    *result = g_new(uint8_t, *result_len);
+    int ret = qcrypto_hash_alg_map[hash->alg].len;
+
+    if (*result_len == 0) {
+        *result_len = ret;
+        *result = g_new(uint8_t, *result_len);
+    } else if (*result_len != ret) {
+        error_setg(errp,
+                   "Result buffer size %zu is smaller than hash %d",
+                   *result_len, ret);
+        return -1;
+    }
 
 
     qcrypto_hash_alg_map[hash->alg].result(ctx, *result_len, *result);
     qcrypto_hash_alg_map[hash->alg].result(ctx, *result_len, *result);