diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -275,6 +275,20 @@ extern u_long pf_ioctl_maxcount; +/* + * Copy a user-provided string, returning an error if truncation would occur. + * Avoid scanning past "sz" bytes in the source string since there's no + * guarantee that it's nul-terminated. + */ +static int +pf_user_strcpy(char *dst, const char *src, size_t sz) +{ + if (strnlen(src, sz) == sz) + return (EINVAL); + (void)strlcpy(dst, src, sz); + return (0); +} + static void pfattach_vnet(void) { @@ -1543,14 +1557,17 @@ strlcpy(pool->ifname, kpool->ifname, sizeof(pool->ifname)); } -static void +static int pf_pooladdr_to_kpooladdr(const struct pf_pooladdr *pool, struct pf_kpooladdr *kpool) { + int ret; bzero(kpool, sizeof(*kpool)); bcopy(&pool->addr, &kpool->addr, sizeof(kpool->addr)); - strlcpy(kpool->ifname, pool->ifname, sizeof(kpool->ifname)); + ret = pf_user_strcpy(kpool->ifname, pool->ifname, + sizeof(kpool->ifname)); + return (ret); } static void @@ -1715,15 +1732,30 @@ bcopy(&rule->src, &krule->src, sizeof(rule->src)); bcopy(&rule->dst, &krule->dst, sizeof(rule->dst)); - strlcpy(krule->label[0], rule->label, sizeof(rule->label)); - strlcpy(krule->ifname, rule->ifname, sizeof(rule->ifname)); - strlcpy(krule->qname, rule->qname, sizeof(rule->qname)); - strlcpy(krule->pqname, rule->pqname, sizeof(rule->pqname)); - strlcpy(krule->tagname, rule->tagname, sizeof(rule->tagname)); - strlcpy(krule->match_tagname, rule->match_tagname, + ret = pf_user_strcpy(krule->label[0], rule->label, sizeof(rule->label)); + if (ret != 0) + return (ret); + ret = pf_user_strcpy(krule->ifname, rule->ifname, sizeof(rule->ifname)); + if (ret != 0) + return (ret); + ret = pf_user_strcpy(krule->qname, rule->qname, sizeof(rule->qname)); + if (ret != 0) + return (ret); + ret = pf_user_strcpy(krule->pqname, rule->pqname, sizeof(rule->pqname)); + if (ret != 0) + return (ret); + ret = pf_user_strcpy(krule->tagname, rule->tagname, + sizeof(rule->tagname)); + if (ret != 0) + return (ret); + ret = pf_user_strcpy(krule->match_tagname, rule->match_tagname, sizeof(rule->match_tagname)); - strlcpy(krule->overload_tblname, rule->overload_tblname, + if (ret != 0) + return (ret); + ret = pf_user_strcpy(krule->overload_tblname, rule->overload_tblname, sizeof(rule->overload_tblname)); + if (ret != 0) + return (ret); ret = pf_pool_to_kpool(&rule->rpool, &krule->rpool); if (ret != 0) @@ -1799,6 +1831,8 @@ pf_state_kill_to_kstate_kill(const struct pfioc_state_kill *psk, struct pf_kstate_kill *kill) { + int ret; + bzero(kill, sizeof(*kill)); bcopy(&psk->psk_pfcmp, &kill->psk_pfcmp, sizeof(kill->psk_pfcmp)); @@ -1806,8 +1840,14 @@ kill->psk_proto = psk->psk_proto; bcopy(&psk->psk_src, &kill->psk_src, sizeof(kill->psk_src)); bcopy(&psk->psk_dst, &kill->psk_dst, sizeof(kill->psk_dst)); - strlcpy(kill->psk_ifname, psk->psk_ifname, sizeof(kill->psk_ifname)); - strlcpy(kill->psk_label, psk->psk_label, sizeof(kill->psk_label)); + ret = pf_user_strcpy(kill->psk_ifname, psk->psk_ifname, + sizeof(kill->psk_ifname)); + if (ret != 0) + return (ret); + ret = pf_user_strcpy(kill->psk_label, psk->psk_label, + sizeof(kill->psk_label)); + if (ret != 0) + return (ret); return (0); } @@ -2369,8 +2409,9 @@ struct pf_krule *tail; int rs_num; - PF_RULES_WLOCK(); pr->anchor[sizeof(pr->anchor) - 1] = 0; + + PF_RULES_WLOCK(); ruleset = pf_find_kruleset(pr->anchor); if (ruleset == NULL) { PF_RULES_WUNLOCK(); @@ -2400,8 +2441,9 @@ struct pf_krule *rule; int rs_num; - PF_RULES_WLOCK(); pr->anchor[sizeof(pr->anchor) - 1] = 0; + + PF_RULES_WLOCK(); ruleset = pf_find_kruleset(pr->anchor); if (ruleset == NULL) { PF_RULES_WUNLOCK(); @@ -2590,6 +2632,8 @@ u_int32_t nr = 0; int rs_num; + pcr->anchor[sizeof(pcr->anchor) - 1] = 0; + if (pcr->action < PF_CHANGE_ADD_HEAD || pcr->action > PF_CHANGE_GET_TICKET) { error = EINVAL; @@ -3041,7 +3085,7 @@ break; } PF_RULES_WLOCK(); - strlcpy(V_pf_status.ifname, pi->ifname, IFNAMSIZ); + error = pf_user_strcpy(V_pf_status.ifname, pi->ifname, IFNAMSIZ); PF_RULES_WUNLOCK(); break; } @@ -3207,19 +3251,23 @@ struct pf_ifspeed_v1 ps; struct ifnet *ifp; - if (psp->ifname[0] != 0) { - /* Can we completely trust user-land? */ - strlcpy(ps.ifname, psp->ifname, IFNAMSIZ); - ifp = ifunit(ps.ifname); - if (ifp != NULL) { - psp->baudrate32 = - (u_int32_t)uqmin(ifp->if_baudrate, UINT_MAX); - if (cmd == DIOCGIFSPEEDV1) - psp->baudrate = ifp->if_baudrate; - } else - error = EINVAL; - } else + if (psp->ifname[0] == '\0') { + error = EINVAL; + break; + } + + error = pf_user_strcpy(ps.ifname, psp->ifname, IFNAMSIZ); + if (error != 0) + break; + ifp = ifunit(ps.ifname); + if (ifp != NULL) { + psp->baudrate32 = + (u_int32_t)uqmin(ifp->if_baudrate, UINT_MAX); + if (cmd == DIOCGIFSPEEDV1) + psp->baudrate = ifp->if_baudrate; + } else { error = EINVAL; + } break; } @@ -3446,7 +3494,9 @@ break; } pa = malloc(sizeof(*pa), M_PFRULE, M_WAITOK); - pf_pooladdr_to_kpooladdr(&pp->addr, pa); + error = pf_pooladdr_to_kpooladdr(&pp->addr, pa); + if (error != 0) + break; if (pa->ifname[0]) kif = pf_kkif_create(M_WAITOK); PF_RULES_WLOCK(); @@ -3482,8 +3532,10 @@ struct pf_kpool *pool; struct pf_kpooladdr *pa; - PF_RULES_RLOCK(); + pp->anchor[sizeof(pp->anchor) - 1] = 0; pp->nr = 0; + + PF_RULES_RLOCK(); pool = pf_get_kpool(pp->anchor, pp->ticket, pp->r_action, pp->r_num, 0, 1, 0); if (pool == NULL) { @@ -3503,6 +3555,8 @@ struct pf_kpooladdr *pa; u_int32_t nr = 0; + pp->anchor[sizeof(pp->anchor) - 1] = 0; + PF_RULES_RLOCK(); pool = pf_get_kpool(pp->anchor, pp->ticket, pp->r_action, pp->r_num, 0, 1, 1); @@ -3534,6 +3588,8 @@ struct pf_kruleset *ruleset; struct pfi_kkif *kif = NULL; + pca->anchor[sizeof(pca->anchor) - 1] = 0; + if (pca->action < PF_CHANGE_ADD_HEAD || pca->action > PF_CHANGE_REMOVE) { error = EINVAL; @@ -3665,8 +3721,9 @@ struct pf_kruleset *ruleset; struct pf_kanchor *anchor; - PF_RULES_RLOCK(); pr->path[sizeof(pr->path) - 1] = 0; + + PF_RULES_RLOCK(); if ((ruleset = pf_find_kruleset(pr->path)) == NULL) { PF_RULES_RUNLOCK(); error = ENOENT; @@ -3693,8 +3750,9 @@ struct pf_kanchor *anchor; u_int32_t nr = 0; - PF_RULES_RLOCK(); pr->path[sizeof(pr->path) - 1] = 0; + + PF_RULES_RLOCK(); if ((ruleset = pf_find_kruleset(pr->path)) == NULL) { PF_RULES_RUNLOCK(); error = ENOENT; @@ -4275,6 +4333,7 @@ } PF_RULES_WLOCK(); for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { + ioe->anchor[sizeof(ioe->anchor) - 1] = '\0'; switch (ioe->rs_num) { #ifdef ALTQ case PF_RULESET_ALTQ: @@ -4348,6 +4407,7 @@ } PF_RULES_WLOCK(); for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { + ioe->anchor[sizeof(ioe->anchor) - 1] = '\0'; switch (ioe->rs_num) { #ifdef ALTQ case PF_RULESET_ALTQ: @@ -4424,6 +4484,7 @@ PF_RULES_WLOCK(); /* First makes sure everything will succeed. */ for (i = 0, ioe = ioes; i < io->size; i++, ioe++) { + ioe->anchor[sizeof(ioe->anchor) - 1] = 0; switch (ioe->rs_num) { #ifdef ALTQ case PF_RULESET_ALTQ: @@ -4490,7 +4551,7 @@ struct pfr_table table; bzero(&table, sizeof(table)); - strlcpy(table.pfrt_anchor, ioe->anchor, + (void)strlcpy(table.pfrt_anchor, ioe->anchor, sizeof(table.pfrt_anchor)); if ((error = pfr_ina_commit(&table, ioe->ticket, NULL, NULL, 0))) {