Mercurial > hg > dhcpcd
changeset 4502:5d361d74621c draft
BSD: Validate RTM message lengths received
Doubtful these lengths would be invalid, but you never know.
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Fri, 03 May 2019 15:44:51 +0100 |
| parents | be15f5b1966c |
| children | 9784c3171a22 |
| files | src/if-bsd.c |
| diffstat | 1 files changed, 74 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/src/if-bsd.c Fri May 03 14:50:28 2019 +0100 +++ b/src/if-bsd.c Fri May 03 15:44:51 2019 +0100 @@ -360,20 +360,28 @@ #endif } -static void -get_addrs(int type, const void *data, const struct sockaddr **sa) +static int +get_addrs(int type, const void *data, size_t data_len, + const struct sockaddr **sa) { - const char *cp; + const char *cp, *ep; int i; cp = data; + ep = cp + data_len; for (i = 0; i < RTAX_MAX; i++) { if (type & (1 << i)) { + if (cp >= ep) { + errno = EINVAL; + return -1; + } sa[i] = (const struct sockaddr *)cp; RT_ADVANCE(cp, sa[i]); } else sa[i] = NULL; } + + return 0; } static struct interface * @@ -647,7 +655,9 @@ } #endif - get_addrs(rtm->rtm_addrs, rtm + 1, rti_info); + if (get_addrs(rtm->rtm_addrs, rtm + 1, + rtm->rtm_msglen - sizeof(*rtm), rti_info) == -1) + return -1; memset(rt, 0, sizeof(*rt)); rt->rt_flags = (unsigned int)rtm->rtm_flags; @@ -713,13 +723,17 @@ end = buf + needed; for (p = buf; p < end; p += rtm->rtm_msglen) { rtm = (void *)p; + if (p + rtm->rtm_msglen >= end) { + errno = EINVAL; + break; + } if (if_copyrt(ctx, &rt, rtm) == 0) { rt.rt_dflags |= RTDF_INIT; rt_recvrt(RTM_ADD, &rt, rtm->rtm_pid); } } free(buf); - return 0; + return p == end ? 0 : -1; } #ifdef INET @@ -981,28 +995,38 @@ } #endif -static void +static int if_announce(struct dhcpcd_ctx *ctx, const struct if_announcemsghdr *ifan) { + if (ifan->ifan_msglen < sizeof(*ifan)) { + errno = EINVAL; + return -1; + } + switch(ifan->ifan_what) { case IFAN_ARRIVAL: - dhcpcd_handleinterface(ctx, 1, ifan->ifan_name); - break; + return dhcpcd_handleinterface(ctx, 1, ifan->ifan_name); case IFAN_DEPARTURE: - dhcpcd_handleinterface(ctx, -1, ifan->ifan_name); - break; + return dhcpcd_handleinterface(ctx, -1, ifan->ifan_name); } + + return 0; } -static void +static int if_ifinfo(struct dhcpcd_ctx *ctx, const struct if_msghdr *ifm) { struct interface *ifp; int link_state; + if (ifm->ifm_msglen < sizeof(*ifm)) { + errno = EINVAL; + return -1; + } + if ((ifp = if_findindex(ctx->ifaces, ifm->ifm_index)) == NULL) - return; + return 0; switch (ifm->ifm_data.ifi_link_state) { case LINK_STATE_UNKNOWN: @@ -1018,19 +1042,25 @@ dhcpcd_handlecarrier(ctx, link_state, (unsigned int)ifm->ifm_flags, ifp->name); + return 0; } -static void +static int if_rtm(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) { struct rt rt; + if (rtm->rtm_msglen < sizeof(*rtm)) { + errno = EINVAL; + return -1; + } + /* Ignore errors. */ if (rtm->rtm_errno != 0) - return; + return 0; if (if_copyrt(ctx, &rt, rtm) == -1) - return; + return -1; #ifdef INET6 /* @@ -1054,9 +1084,10 @@ #endif rt_recvrt(rtm->rtm_type, &rt, rtm->rtm_pid); + return 0; } -static void +static int if_ifa(struct dhcpcd_ctx *ctx, const struct ifa_msghdr *ifam) { struct interface *ifp; @@ -1064,11 +1095,18 @@ int addrflags; pid_t pid; + if (ifam->ifam_msglen < sizeof(*ifam)) { + errno = EINVAL; + return -1; + } + if ((ifp = if_findindex(ctx->ifaces, ifam->ifam_index)) == NULL) - return; - get_addrs(ifam->ifam_addrs, ifam + 1, rti_info); + return 0; + if (get_addrs(ifam->ifam_addrs, ifam + 1, + ifam->ifam_msglen - sizeof(*ifam), rti_info) == -1) + return -1; if (rti_info[RTAX_IFA] == NULL) - return; + return 0; #ifdef HAVE_IFAM_PID pid = ifam->ifam_pid; @@ -1168,7 +1206,7 @@ } freeifaddrs(ifaddrs); if (ifa != NULL) - return; + return 0; #endif } @@ -1231,40 +1269,37 @@ } #endif } + + return 0; } -static void +static int if_dispatch(struct dhcpcd_ctx *ctx, const struct rt_msghdr *rtm) { if (rtm->rtm_version != RTM_VERSION) - return; + return 0; switch(rtm->rtm_type) { #ifdef RTM_IFANNOUNCE case RTM_IFANNOUNCE: - if_announce(ctx, (const void *)rtm); - break; + return if_announce(ctx, (const void *)rtm); #endif case RTM_IFINFO: - if_ifinfo(ctx, (const void *)rtm); - break; + return if_ifinfo(ctx, (const void *)rtm); case RTM_ADD: /* FALLTHROUGH */ case RTM_CHANGE: /* FALLTHROUGH */ case RTM_DELETE: - if_rtm(ctx, (const void *)rtm); - break; + return if_rtm(ctx, (const void *)rtm); #ifdef RTM_CHGADDR case RTM_CHGADDR: /* FALLTHROUGH */ #endif case RTM_DELADDR: /* FALLTHROUGH */ case RTM_NEWADDR: - if_ifa(ctx, (const void *)rtm); - break; + return if_ifa(ctx, (const void *)rtm); #ifdef RTM_DESYNC case RTM_DESYNC: - dhcpcd_linkoverflow(ctx); - break; + return dhcpcd_linkoverflow(ctx); #endif } } @@ -1280,9 +1315,13 @@ len = recvmsg(ctx->link_fd, &msg, 0); if (len == -1) return -1; - if (len != 0) - if_dispatch(ctx, &rtm.hdr); - return 0; + if (len == 0) + return 0; + if (len < rtm.hdr.rtm_msglen) { + errno = EINVAL; + return -1; + } + return if_dispatch(ctx, &rtm.hdr); } #ifndef SYS_NMLN /* OSX */
