summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2005-02-15 23:18:56 +0000
committerBrad Smith <brad@cvs.openbsd.org>2005-02-15 23:18:56 +0000
commite0357791ec134fdab9c5a020c442f357df3d1bec (patch)
treed1472db9411e2c74f1290db8398d666d2fa9e49a
parentb01f50e218e192ef42e3ac5b8e45f23ca6a7985f (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@
-rw-r--r--sys/net/if_media.c64
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;
}