diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c --- a/sys/netinet/in_pcb.c +++ b/sys/netinet/in_pcb.c @@ -2266,8 +2266,10 @@ continue; if (__predict_true(inp_smr_lock(inp, lockflags))) { - if (__predict_true(in_pcblookup_wild_match(inp, laddr, - lport) != INPLOOKUP_MATCH_NONE)) + match = in_pcblookup_wild_match(inp, laddr, lport); + if (match != INPLOOKUP_MATCH_NONE && + prison_check_ip4_locked(inp->inp_cred->cr_prison, + &laddr) == 0) return (inp); inp_unlock(inp, lockflags); } @@ -2515,9 +2517,10 @@ * Insert the PCB into a hash chain using ordering rules which ensure that * in_pcblookup_hash_wild_*() always encounter the highest-ranking PCB first. * - * Specifically, keep jailed PCBs in front of non-jailed PCBs, and keep PCBs - * with exact local addresses ahead of wildcard PCBs. Unbound v4-mapped v6 PCBs - * always appear last no matter whether they are jailed. + * The rank is determined by whether the socket belongs to a (classic) jail, and + * whether it is bound to a specific address. Jailed sockets bound to an + * address are ranked higher than non-jailed sockets, and jailed sockets without + * a source address are ranked lower than non-jailed sockets. */ static void _in_pcbinshash_wild(struct inpcbhead *pcbhash, struct inpcb *inp) @@ -2540,25 +2543,24 @@ CK_LIST_INSERT_HEAD(pcbhash, inp, inp_hash_wild); return; } - injail = in_pcbjailed(inp, PR_IP4); - if (!injail) { + if (!bound) { CK_LIST_FOREACH(last, pcbhash, inp_hash_wild) { - if (!in_pcbjailed(last, PR_IP4)) + if (last->inp_laddr.s_addr == INADDR_ANY && !injail) break; if (CK_LIST_NEXT(last, inp_hash_wild) == NULL) { CK_LIST_INSERT_AFTER(last, inp, inp_hash_wild); return; } } - } else if (!CK_LIST_EMPTY(pcbhash) && - !in_pcbjailed(CK_LIST_FIRST(pcbhash), PR_IP4)) { - CK_LIST_INSERT_HEAD(pcbhash, inp, inp_hash_wild); - return; - } - if (!bound) { - CK_LIST_FOREACH_FROM(last, pcbhash, inp_hash_wild) { - if (last->inp_laddr.s_addr == INADDR_ANY) + } else { + if (injail) { + CK_LIST_INSERT_HEAD(pcbhash, inp, inp_hash_wild); + return; + } + CK_LIST_FOREACH(last, pcbhash, inp_hash_wild) { + if (last->inp_laddr.s_addr == INADDR_ANY || + !in_pcbjailed(last, PR_IP4)) break; if (CK_LIST_NEXT(last, inp_hash_wild) == NULL) { CK_LIST_INSERT_AFTER(last, inp, inp_hash_wild); @@ -2588,23 +2590,24 @@ last = NULL; bound = !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr); injail = in_pcbjailed(inp, PR_IP6); - if (!injail) { + if (!bound) { CK_LIST_FOREACH(last, pcbhash, inp_hash_wild) { - if (!in_pcbjailed(last, PR_IP6)) + if (IN6_IS_ADDR_UNSPECIFIED(&last->in6p_laddr) && + !injail) break; if (CK_LIST_NEXT(last, inp_hash_wild) == NULL) { CK_LIST_INSERT_AFTER(last, inp, inp_hash_wild); return; } } - } else if (!CK_LIST_EMPTY(pcbhash) && - !in_pcbjailed(CK_LIST_FIRST(pcbhash), PR_IP6)) { - CK_LIST_INSERT_HEAD(pcbhash, inp, inp_hash_wild); - return; - } - if (!bound) { - CK_LIST_FOREACH_FROM(last, pcbhash, inp_hash_wild) { - if (IN6_IS_ADDR_UNSPECIFIED(&last->in6p_laddr)) + } else { + if (injail) { + CK_LIST_INSERT_HEAD(pcbhash, inp, inp_hash_wild); + return; + } + CK_LIST_FOREACH(last, pcbhash, inp_hash_wild) { + if (IN6_IS_ADDR_UNSPECIFIED(&last->in6p_laddr) || + !in_pcbjailed(last, PR_IP6)) break; if (CK_LIST_NEXT(last, inp_hash_wild) == NULL) { CK_LIST_INSERT_AFTER(last, inp, inp_hash_wild); diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c --- a/sys/netinet6/in6_pcb.c +++ b/sys/netinet6/in6_pcb.c @@ -1021,8 +1021,10 @@ continue; if (__predict_true(inp_smr_lock(inp, lockflags))) { - if (__predict_true(in6_pcblookup_wild_match(inp, laddr, - lport) != INPLOOKUP_MATCH_NONE)) + match = in6_pcblookup_wild_match(inp, laddr, lport); + if (match != INPLOOKUP_MATCH_NONE && + prison_check_ip6_locked(inp->inp_cred->cr_prison, + laddr) == 0) return (inp); inp_unlock(inp, lockflags); }