[31515] in CVS-changelog-for-Kerberos-V5
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