diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2005-02-15 23:18:56 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2005-02-15 23:18:56 +0000 |
commit | e0357791ec134fdab9c5a020c442f357df3d1bec (patch) | |
tree | d1472db9411e2c74f1290db8398d666d2fa9e49a /sys/net | |
parent | b01f50e218e192ef42e3ac5b8e45f23ca6a7985f (diff) |
rev 1.19
Avoid DoS attack by setting ifm->ifm_media to a high number and running the
kernel out of memory.
From NetBSD
Fixes panic mentioned in PR 4088.
ok krw@ mcbride@ dhartmei@
Diffstat (limited to 'sys/net')
-rw-r--r-- | sys/net/if_media.c | 64 |
1 files changed, 24 insertions, 40 deletions
diff --git a/sys/net/if_media.c b/sys/net/if_media.c index 662d3f0800a..f4609f43b87 100644 --- a/sys/net/if_media.c +++ b/sys/net/if_media.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_media.c,v 1.10 2003/12/10 07:22:42 itojun Exp $ */ +/* $OpenBSD: if_media.c,v 1.11 2005/02/15 23:18:55 brad Exp $ */ /* $NetBSD: if_media.c,v 1.10 2000/03/13 23:52:39 soren Exp $ */ /*- @@ -223,7 +223,7 @@ ifmedia_ioctl(ifp, ifr, ifm, cmd) { struct ifmedia_entry *match; struct ifmediareq *ifmr = (struct ifmediareq *) ifr; - int error = 0, sticky; + int error = 0; if (ifp == NULL || ifr == NULL || ifm == NULL) return (EINVAL); @@ -292,9 +292,10 @@ ifmedia_ioctl(ifp, ifr, ifm, cmd) case SIOCGIFMEDIA: { struct ifmedia_entry *ep; - int *kptr, count; + size_t nwords; - kptr = NULL; /* XXX gcc */ + if(ifmr->ifm_count < 0) + return (EINVAL); ifmr->ifm_active = ifmr->ifm_current = ifm->ifm_cur ? ifm->ifm_cur->ifm_media : IFM_NONE; @@ -302,53 +303,36 @@ ifmedia_ioctl(ifp, ifr, ifm, cmd) ifmr->ifm_status = 0; (*ifm->ifm_status)(ifp, ifmr); - count = 0; + /* + * Count them so we know a-priori how much is the max we'll + * need. + */ ep = TAILQ_FIRST(&ifm->ifm_list); + for (nwords = 0; ep != NULL; ep = TAILQ_NEXT(ep, ifm_list)) + nwords++; if (ifmr->ifm_count != 0) { - kptr = (int *)malloc(ifmr->ifm_count * sizeof(int), - M_TEMP, M_WAITOK); - + size_t count; + size_t minwords = nwords > (size_t)ifmr->ifm_count + ? (size_t)ifmr->ifm_count + : nwords; + int *kptr = (int *)malloc(minwords * sizeof(int), + M_TEMP, M_WAITOK); /* * Get the media words from the interface's list. */ - for (; ep != NULL && count < ifmr->ifm_count; + ep = TAILQ_FIRST(&ifm->ifm_list); + for (count = 0; ep != NULL && count < minwords; ep = TAILQ_NEXT(ep, ifm_list), count++) kptr[count] = ep->ifm_media; - if (ep != NULL) + error = copyout(kptr, ifmr->ifm_ulist, + minwords * sizeof(int)); + if (error == 0 && ep != NULL) error = E2BIG; /* oops! */ - } - - /* - * If there are more interfaces on the list, count - * them. This allows the caller to set ifmr->ifm_count - * to 0 on the first call to know how much space to - * callocate. - */ - for (; ep != NULL; ep = TAILQ_NEXT(ep, ifm_list)) - count++; - - /* - * We do the copyout on E2BIG, because that's - * just our way of telling userland that there - * are more. This is the behavior I've observed - * under BSD/OS 3.0 - */ - sticky = error; - if ((error == 0 || error == E2BIG) && ifmr->ifm_count != 0) { - error = copyout((caddr_t)kptr, - (caddr_t)ifmr->ifm_ulist, - ifmr->ifm_count * sizeof(int)); - } - - if (error == 0) - error = sticky; - - if (ifmr->ifm_count != 0) free(kptr, M_TEMP); - - ifmr->ifm_count = count; + } + ifmr->ifm_count = nwords; break; } |