Module Name: src Committed By: pgoyette Date: Mon Jan 29 02:02:14 UTC 2018
Modified Files: src/sys/netinet6: nd6.c Log Message: Use existing fill_[pd]rlist() functions to calculate size of buffer to allocate, rather than relying on an arbitrary length passed in from userland. Allow copyout() of partial results if the user buffer is too small, to be consistent with the way sysctl(3) is documented. Garbage-collect now-unused third parrameter in the fill_[pd]rlist() functions. As discussed on IRC. OK kamil@ and christos@ XXX Needs pull-up to netbsd-8 branch. To generate a diff of this commit: cvs rdiff -u -r1.240 -r1.241 src/sys/netinet6/nd6.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netinet6/nd6.c diff -u src/sys/netinet6/nd6.c:1.240 src/sys/netinet6/nd6.c:1.241 --- src/sys/netinet6/nd6.c:1.240 Fri Dec 15 04:03:46 2017 +++ src/sys/netinet6/nd6.c Mon Jan 29 02:02:14 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: nd6.c,v 1.240 2017/12/15 04:03:46 ozaki-r Exp $ */ +/* $NetBSD: nd6.c,v 1.241 2018/01/29 02:02:14 pgoyette Exp $ */ /* $KAME: nd6.c,v 1.279 2002/06/08 11:16:51 itojun Exp $ */ /* @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.240 2017/12/15 04:03:46 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: nd6.c,v 1.241 2018/01/29 02:02:14 pgoyette Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -124,8 +124,8 @@ static callout_t nd6_timer_ch; static struct workqueue *nd6_timer_wq; static struct work nd6_timer_wk; -static int fill_drlist(void *, size_t *, size_t); -static int fill_prlist(void *, size_t *, size_t); +static int fill_drlist(void *, size_t *); +static int fill_prlist(void *, size_t *); static struct ifnet *nd6_defifp; static int nd6_defifindex; @@ -2491,6 +2491,7 @@ nd6_sysctl( size_t ol; int error; size_t bufsize = 0; + int (*fill_func)(void *, size_t *); error = 0; @@ -2500,22 +2501,17 @@ nd6_sysctl( return EINVAL; ol = oldlenp ? *oldlenp : 0; - if (oldp && *oldlenp > 0) { - p = kmem_alloc(*oldlenp, KM_SLEEP); - bufsize = *oldlenp; - } else - p = NULL; + p = NULL; + + fill_func = NULL; + switch (name) { case ICMPV6CTL_ND6_DRLIST: - error = fill_drlist(p, oldlenp, ol); - if (!error && p != NULL && oldp != NULL) - error = copyout(p, oldp, *oldlenp); + fill_func = fill_drlist; break; case ICMPV6CTL_ND6_PRLIST: - error = fill_prlist(p, oldlenp, ol); - if (!error && p != NULL && oldp != NULL) - error = copyout(p, oldp, *oldlenp); + fill_func = fill_prlist; break; case ICMPV6CTL_ND6_MAXQLEN: @@ -2525,6 +2521,19 @@ nd6_sysctl( error = ENOPROTOOPT; break; } + + if (fill_func) { + error = (*fill_func)(p, oldlenp); /* calc len needed */ + if (error == 0 && oldp && *oldlenp > 0 ) { + p = kmem_alloc(*oldlenp, KM_SLEEP); + bufsize = *oldlenp; + error = (*fill_func)(p, oldlenp); + if (!error && oldp != NULL) + error = copyout(p, oldp, min(ol, *oldlenp)); + if (*oldlenp > ol) + error = ENOMEM; + } + } if (p) kmem_free(p, bufsize); @@ -2532,7 +2541,7 @@ nd6_sysctl( } static int -fill_drlist(void *oldp, size_t *oldlenp, size_t ol) +fill_drlist(void *oldp, size_t *oldlenp) { int error = 0; struct in6_defrouter *d = NULL, *de = NULL; @@ -2571,10 +2580,6 @@ fill_drlist(void *oldp, size_t *oldlenp, } ND6_UNLOCK(); - if (oldp) { - if (l > ol) - error = ENOMEM; - } if (oldlenp) *oldlenp = l; /* (void *)d - (void *)oldp */ @@ -2582,7 +2587,7 @@ fill_drlist(void *oldp, size_t *oldlenp, } static int -fill_prlist(void *oldp, size_t *oldlenp, size_t ol) +fill_prlist(void *oldp, size_t *oldlenp) { int error = 0; struct nd_prefix *pr; @@ -2678,11 +2683,7 @@ fill_prlist(void *oldp, size_t *oldlenp, } ND6_UNLOCK(); - if (oldp) { - *oldlenp = l; /* (void *)d - (void *)oldp */ - if (l > ol) - error = ENOMEM; - } else + if (oldlenp) *oldlenp = l; return error;