diff options
author | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2024-04-06 14:23:28 +0000 |
---|---|---|
committer | Alexander Bluhm <bluhm@cvs.openbsd.org> | 2024-04-06 14:23:28 +0000 |
commit | a6fc509dacb6ee685d1eeb20c41d8993f7369c9b (patch) | |
tree | 7ad44469e898c15927ef16b73243f115d2889ed7 /sys/netinet | |
parent | de67e679224b59adc382c26f491fc06e0b3593c6 (diff) |
IP multicast sysctl mrtmfc must not write outside of allocation.
Reading sysctl mrt_sysctl_mfc() allocates memory to be copied back
to user. Chunks of struct mfcinfo are copied from routing table
to linear heap memory. If the allocated memory was not a multiple
the struct size, a struct mfcinfo could be copied to a partially
unallocated destination. Check that the end of the struct is within
the allocation.
From Alfredo Ortega; OK claudio@
Diffstat (limited to 'sys/netinet')
-rw-r--r-- | sys/netinet/ip_mroute.c | 21 |
1 files changed, 10 insertions, 11 deletions
diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c index 3e9b00ec265..1913b1767a1 100644 --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ip_mroute.c,v 1.141 2024/02/11 18:14:26 mvs Exp $ */ +/* $OpenBSD: ip_mroute.c,v 1.142 2024/04/06 14:23:27 bluhm Exp $ */ /* $NetBSD: ip_mroute.c,v 1.85 2004/04/26 01:31:57 matt Exp $ */ /* @@ -430,8 +430,9 @@ mrt_rtwalk_mfcsysctl(struct rtentry *rt, void *arg, unsigned int rtableid) } for (minfo = msa->msa_minfos; - (uint8_t *)minfo < ((uint8_t *)msa->msa_minfos + msa->msa_len); - minfo++) { + (uint8_t *)(minfo + 1) <= + (uint8_t *)msa->msa_minfos + msa->msa_len; + minfo++) { /* Find a new entry or update old entry. */ if (minfo->mfc_origin.s_addr != satosin(rt->rt_gateway)->sin_addr.s_addr || @@ -471,13 +472,11 @@ mrt_sysctl_mfc(void *oldp, size_t *oldlenp) if (oldp != NULL && *oldlenp > MAXPHYS) return (EINVAL); - if (oldp != NULL) + memset(&msa, 0, sizeof(msa)); + if (oldp != NULL && *oldlenp > 0) { msa.msa_minfos = malloc(*oldlenp, M_TEMP, M_WAITOK | M_ZERO); - else - msa.msa_minfos = NULL; - - msa.msa_len = *oldlenp; - msa.msa_needed = 0; + msa.msa_len = *oldlenp; + } for (rtableid = 0; rtableid <= RT_TABLEID_MAX; rtableid++) { rtable_walk(rtableid, AF_INET, NULL, mrt_rtwalk_mfcsysctl, @@ -486,11 +485,11 @@ mrt_sysctl_mfc(void *oldp, size_t *oldlenp) if (msa.msa_minfos != NULL && msa.msa_needed > 0 && (error = copyout(msa.msa_minfos, oldp, msa.msa_needed)) != 0) { - free(msa.msa_minfos, M_TEMP, *oldlenp); + free(msa.msa_minfos, M_TEMP, msa.msa_len); return (error); } - free(msa.msa_minfos, M_TEMP, *oldlenp); + free(msa.msa_minfos, M_TEMP, msa.msa_len); *oldlenp = msa.msa_needed; return (0); |