[31515] in CVS-changelog-for-Kerberos-V5

home help back first fref pref prev next nref lref last post

krb5 commit: Avoid undefined memcpy/memmove invocations

daemon@ATHENA.MIT.EDU (ghudson@mit.edu)
Thu Apr 9 02:29:46 2026

From: ghudson@mit.edu
To: cvs-krb5@mit.edu
Message-Id: <20260409062937.4F019104ACC@krbdev.mit.edu>
Date: Thu,  9 Apr 2026 02:29:37 -0400 (EDT)
MIME-Version: 1.0
Reply-To: krbdev@mit.edu
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: 7bit
Errors-To: cvs-krb5-bounces@mit.edu

https://github.com/krb5/krb5/commit/a2d2e2849ea0968ef81e74983f0ec4a0258d9eee
commit a2d2e2849ea0968ef81e74983f0ec4a0258d9eee
Author: Greg Hudson <ghudson@mit.edu>
Date:   Fri Apr 3 19:33:50 2026 -0400

    Avoid undefined memcpy/memmove invocations
    
    Where memcpy() or memmove() might be invoked with null input or output
    pointers, add checks for non-zero length.  For brevity, add helpers
    k5memcpy() and k5memmove() and use them in files that include
    k5-int.h.
    
    Most of the potential undefined invocations were reported by Evgeny
    Shemyakin.

 src/include/k5-int.h                               | 16 ++++++++++++++++
 src/kadmin/server/ipropd_svc.c                     |  3 ++-
 src/kdc/fast_util.c                                |  2 +-
 src/kdc/rtest.c                                    |  2 +-
 src/lib/crypto/builtin/kdf.c                       |  2 +-
 src/lib/crypto/krb/aead.c                          |  6 ++++--
 src/lib/crypto/krb/cf2.c                           |  2 +-
 src/lib/gssapi/krb5/prf.c                          |  2 +-
 src/lib/krb5/asn.1/asn1_encode.c                   |  4 ++--
 src/lib/krb5/krb/serialize.c                       |  2 +-
 src/lib/rpc/xdr_mem.c                              |  6 ++++--
 src/plugins/kdb/db2/libdb2/btree/btree.h           |  6 ++++--
 src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c         |  2 +-
 src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c |  2 +-
 src/util/support/hashtab.c                         |  3 ++-
 15 files changed, 42 insertions(+), 18 deletions(-)

diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index cfd2cc939..56d9d1b20 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -2313,6 +2313,22 @@ k5memdup0(const void *in, size_t len, krb5_error_code *code)
     return ptr;
 }
 
+/* memcpy if len > 0, to avoid passing null pointers (which is undefined). */
+static inline void
+k5memcpy(void *dest, const void *src, size_t len)
+{
+    if (len > 0)
+        memcpy(dest, src, len);
+}
+
+/* memmove if len > 0, to avoid passing null pointers (which is undefined). */
+static inline void
+k5memmove(void *dest, const void *src, size_t len)
+{
+    if (len > 0)
+        memmove(dest, src, len);
+}
+
 /* Convert a krb5_timestamp to a time_t value, treating the negative range of
  * krb5_timestamp as times between 2038 and 2106 (if time_t is 64-bit). */
 static inline time_t
diff --git a/src/kadmin/server/ipropd_svc.c b/src/kadmin/server/ipropd_svc.c
index e5dd233e8..108c29e30 100644
--- a/src/kadmin/server/ipropd_svc.c
+++ b/src/kadmin/server/ipropd_svc.c
@@ -122,7 +122,8 @@ buf_to_string(gss_buffer_desc *b)
     char *s = malloc(b->length+1);
 
     if (s) {
-	memcpy(s, b->value, b->length);
+	if (b->length > 0)
+	    memcpy(s, b->value, b->length);
 	s[b->length] = 0;
     }
     (void) gss_release_buffer(&min_stat, b);
diff --git a/src/kdc/fast_util.c b/src/kdc/fast_util.c
index 7a6579f1d..848f80816 100644
--- a/src/kdc/fast_util.c
+++ b/src/kdc/fast_util.c
@@ -453,7 +453,7 @@ make_padata(krb5_preauthtype pa_type, const void *contents, size_t len,
 {
     if (k5_alloc_pa_data(pa_type, len, out) != 0)
         return ENOMEM;
-    memcpy((*out)->contents, contents, len);
+    k5memcpy((*out)->contents, contents, len);
     return 0;
 }
 
diff --git a/src/kdc/rtest.c b/src/kdc/rtest.c
index 685228411..06e442da9 100644
--- a/src/kdc/rtest.c
+++ b/src/kdc/rtest.c
@@ -85,7 +85,7 @@ main(int argc, char **argv)
         otrans.data = (char *) malloc(otrans.length);
     else
         otrans.data = 0;
-    memcpy(otrans.data,argv[1], otrans.length);
+    k5memcpy(otrans.data,argv[1], otrans.length);
 
     tgs = make_princ(ctx, argv[2], argv[0]);
     cl  = make_princ(ctx, argv[3], argv[0]);
diff --git a/src/lib/crypto/builtin/kdf.c b/src/lib/crypto/builtin/kdf.c
index 8a6658bfd..8109d7c10 100644
--- a/src/lib/crypto/builtin/kdf.c
+++ b/src/lib/crypto/builtin/kdf.c
@@ -67,7 +67,7 @@ k5_sp800_108_counter_hmac(const struct krb5_hash_provider *hash,
 
     ret = krb5int_hmac(hash, key, iov, 5, &prf);
     if (!ret)
-        memcpy(rnd_out->data, prf.data, rnd_out->length);
+        k5memcpy(rnd_out->data, prf.data, rnd_out->length);
     zapfree(prf.data, prf.length);
     return ret;
 }
diff --git a/src/lib/crypto/krb/aead.c b/src/lib/crypto/krb/aead.c
index 9d4e206ab..8a3220441 100644
--- a/src/lib/crypto/krb/aead.c
+++ b/src/lib/crypto/krb/aead.c
@@ -179,7 +179,8 @@ k5_iov_cursor_get(struct iov_cursor *cursor, unsigned char *block)
         if (nbytes > remain)
             nbytes = remain;
 
-        memcpy(block + bsz - remain, iov->data.data + cursor->in_pos, nbytes);
+        k5memcpy(block + bsz - remain, iov->data.data + cursor->in_pos,
+                 nbytes);
         cursor->in_pos += nbytes;
         remain -= nbytes;
 
@@ -211,7 +212,8 @@ k5_iov_cursor_put(struct iov_cursor *cursor, unsigned char *block)
         if (nbytes > remain)
             nbytes = remain;
 
-        memcpy(iov->data.data + cursor->out_pos, block + bsz - remain, nbytes);
+        k5memcpy(iov->data.data + cursor->out_pos, block + bsz - remain,
+                 nbytes);
         cursor->out_pos += nbytes;
         remain -= nbytes;
 
diff --git a/src/lib/crypto/krb/cf2.c b/src/lib/crypto/krb/cf2.c
index 2ee5aebda..5f86383f1 100644
--- a/src/lib/crypto/krb/cf2.c
+++ b/src/lib/crypto/krb/cf2.c
@@ -61,7 +61,7 @@ krb5_c_prfplus(krb5_context context, const krb5_keyblock *k,
 
     /* Concatenate PRF(k, 1||input) || PRF(k, 2||input) || ... to produce the
      * desired number of bytes. */
-    memcpy(&prf_in.data[1], input->data, input->length);
+    k5memcpy(&prf_in.data[1], input->data, input->length);
     for (i = 0; i < nblocks; i++) {
         prf_in.data[0] = i + 1;
         ret = krb5_c_prf(context, k, &prf_in, &prf_out);
diff --git a/src/lib/gssapi/krb5/prf.c b/src/lib/gssapi/krb5/prf.c
index f87957bdf..0f1b5baab 100644
--- a/src/lib/gssapi/krb5/prf.c
+++ b/src/lib/gssapi/krb5/prf.c
@@ -111,7 +111,7 @@ krb5_gss_pseudo_random(OM_uint32 *minor_status,
     if (t.data == NULL)
         goto cleanup;
 
-    memcpy(ns.data + 4, prf_in->value, prf_in->length);
+    k5memcpy(ns.data + 4, prf_in->value, prf_in->length);
     i = 0;
     p = (unsigned char *)prf_out->value;
     while (desired_output_len > 0) {
diff --git a/src/lib/krb5/asn.1/asn1_encode.c b/src/lib/krb5/asn.1/asn1_encode.c
index 7aebe60db..6fdc3d4f2 100644
--- a/src/lib/krb5/asn.1/asn1_encode.c
+++ b/src/lib/krb5/asn.1/asn1_encode.c
@@ -49,8 +49,8 @@ insert_byte(asn1buf *buf, uint8_t o)
 static inline void
 insert_bytes(asn1buf *buf, const void *bytes, size_t len)
 {
-    if (buf->ptr != NULL && len > 0) {
-        memcpy(buf->ptr - len, bytes, len);
+    if (buf->ptr != NULL) {
+        k5memcpy(buf->ptr - len, bytes, len);
         buf->ptr -= len;
     }
     buf->count += len;
diff --git a/src/lib/krb5/krb/serialize.c b/src/lib/krb5/krb/serialize.c
index 8934cf154..e5aee839b 100644
--- a/src/lib/krb5/krb/serialize.c
+++ b/src/lib/krb5/krb/serialize.c
@@ -67,7 +67,7 @@ krb5_error_code KRB5_CALLCONV
 krb5_ser_pack_bytes(krb5_octet *ostring, size_t osize, krb5_octet **bufp, size_t *remainp)
 {
     if (*remainp >= osize) {
-        memcpy(*bufp, ostring, osize);
+        k5memcpy(*bufp, ostring, osize);
         *bufp += osize;
         *remainp -= osize;
         return(0);
diff --git a/src/lib/rpc/xdr_mem.c b/src/lib/rpc/xdr_mem.c
index 8d3f12017..ea8b76168 100644
--- a/src/lib/rpc/xdr_mem.c
+++ b/src/lib/rpc/xdr_mem.c
@@ -129,7 +129,8 @@ xdrmem_getbytes(XDR *xdrs, caddr_t addr, u_int len)
 		return (FALSE);
 	else
 		xdrs->x_handy -= len;
-	memmove(addr, xdrs->x_private, len);
+	if (len > 0)
+		memmove(addr, xdrs->x_private, len);
 	xdrs->x_private = (char *)xdrs->x_private + len;
 	return (TRUE);
 }
@@ -142,7 +143,8 @@ xdrmem_putbytes(XDR *xdrs, caddr_t addr, u_int len)
 		return (FALSE);
 	else
 		xdrs->x_handy -= len;
-	memmove(xdrs->x_private, addr, len);
+	if (len > 0)
+		memmove(xdrs->x_private, addr, len);
 	xdrs->x_private = (char *)xdrs->x_private + len;
 	return (TRUE);
 }
diff --git a/src/plugins/kdb/db2/libdb2/btree/btree.h b/src/plugins/kdb/db2/libdb2/btree/btree.h
index 91fd271bf..37dc4fda1 100644
--- a/src/plugins/kdb/db2/libdb2/btree/btree.h
+++ b/src/plugins/kdb/db2/libdb2/btree/btree.h
@@ -196,9 +196,11 @@ typedef struct _bleaf {
 	p += sizeof(u_int32_t);						\
 	*(u_char *)p = flags;						\
 	p += sizeof(u_char);						\
-	memmove(p, key->data, key->size);				\
+	if (key->size > 0)						\
+	    memmove(p, key->data, key->size);				\
 	p += key->size;							\
-	memmove(p, data->data, data->size);				\
+	if (data->size > 0)						\
+	    memmove(p, data->data, data->size);				\
 }
 
 /* For the recno leaf pages, the item is a data entry. */
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c b/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c
index ae51905ae..bd59aec6d 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/kdb_xdr.c
@@ -73,7 +73,7 @@ krb5_dbe_update_tl_data(krb5_context context, krb5_db_entry *entry,
     tl_data->tl_data_type = new_tl_data->tl_data_type;
     tl_data->tl_data_length = new_tl_data->tl_data_length;
     tl_data->tl_data_contents = tmp;
-    memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length);
+    k5memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length);
 
     return(0);
 }
diff --git a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
index ae4e03f8c..418d253d1 100644
--- a/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
+++ b/src/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c
@@ -637,7 +637,7 @@ tl_data2berval (krb5_tl_data *in, struct berval **out)
     }
 
     STORE16_INT((*out)->bv_val, in->tl_data_type);
-    memcpy ((*out)->bv_val + 2, in->tl_data_contents, in->tl_data_length);
+    k5memcpy((*out)->bv_val + 2, in->tl_data_contents, in->tl_data_length);
 
     return 0;
 }
diff --git a/src/util/support/hashtab.c b/src/util/support/hashtab.c
index a66b8cb43..1a92ec0d2 100644
--- a/src/util/support/hashtab.c
+++ b/src/util/support/hashtab.c
@@ -94,7 +94,8 @@ siphash24(const uint8_t *data, size_t len, uint64_t k0, uint64_t k1)
     }
 
     /* Process the last 0-7 bytes followed by the length mod 256. */
-    memcpy(last, end, len % 8);
+    if (len % 8 > 0)
+        memcpy(last, end, len % 8);
     last[7] = len & 0xFF;
     mi = load_64_le(last);
     v3 ^= mi;
_______________________________________________
cvs-krb5 mailing list
cvs-krb5@mit.edu
https://mailman.mit.edu/mailman/listinfo/cvs-krb5

home help back first fref pref prev next nref lref last post