inpcb: Fix some bugs in _in_pcbinshash_wild()
- In _in_pcbinshash_wild(), we should avoid returning v6 sockets unless
no other matches are available. This preserves pre-existing
semantics.
- Fix an inverted test: when inserting a non-jailed PCB, we want to
search for the first non-jailed PCB in the hash chain.
- Test the right PCB when searching for a non-jailed PCB.
While here, add a required locking assertion.
Fixes: 7b92493ab1 ("inpcb: Avoid inp_cred dereferences in SMR-protected lookup")
This commit is contained in:
+17
-3
@@ -2506,7 +2506,8 @@ in_pcbjailed(const struct inpcb *inp, unsigned int flag)
|
||||
* 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.
|
||||
* with exact local addresses ahead of wildcard PCBs. Unbound v4-mapped v6 PCBs
|
||||
* always appear last no matter whether they are jailed.
|
||||
*/
|
||||
static void
|
||||
_in_pcbinshash_wild(struct inpcbhead *pcbhash, struct inpcb *inp)
|
||||
@@ -2514,14 +2515,26 @@ _in_pcbinshash_wild(struct inpcbhead *pcbhash, struct inpcb *inp)
|
||||
struct inpcb *last;
|
||||
bool bound, injail;
|
||||
|
||||
INP_LOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
|
||||
last = NULL;
|
||||
bound = inp->inp_laddr.s_addr != INADDR_ANY;
|
||||
if (!bound && (inp->inp_vflag & INP_IPV6PROTO) != 0) {
|
||||
CK_LIST_FOREACH(last, pcbhash, inp_hash_wild) {
|
||||
if (CK_LIST_NEXT(last, inp_hash_wild) == NULL) {
|
||||
CK_LIST_INSERT_AFTER(last, inp, inp_hash_wild);
|
||||
return;
|
||||
}
|
||||
}
|
||||
CK_LIST_INSERT_HEAD(pcbhash, inp, inp_hash_wild);
|
||||
return;
|
||||
}
|
||||
|
||||
injail = in_pcbjailed(inp, PR_IP4);
|
||||
if (!injail) {
|
||||
CK_LIST_FOREACH(last, pcbhash, inp_hash_wild) {
|
||||
if (in_pcbjailed(inp, PR_IP4))
|
||||
if (!in_pcbjailed(last, PR_IP4))
|
||||
break;
|
||||
if (CK_LIST_NEXT(last, inp_hash_wild) == NULL) {
|
||||
CK_LIST_INSERT_AFTER(last, inp, inp_hash_wild);
|
||||
@@ -2559,6 +2572,7 @@ _in6_pcbinshash_wild(struct inpcbhead *pcbhash, struct inpcb *inp)
|
||||
struct inpcb *last;
|
||||
bool bound, injail;
|
||||
|
||||
INP_LOCK_ASSERT(inp);
|
||||
INP_HASH_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
|
||||
last = NULL;
|
||||
@@ -2566,7 +2580,7 @@ _in6_pcbinshash_wild(struct inpcbhead *pcbhash, struct inpcb *inp)
|
||||
injail = in_pcbjailed(inp, PR_IP6);
|
||||
if (!injail) {
|
||||
CK_LIST_FOREACH(last, pcbhash, inp_hash_wild) {
|
||||
if (in_pcbjailed(last, PR_IP6))
|
||||
if (!in_pcbjailed(last, PR_IP6))
|
||||
break;
|
||||
if (CK_LIST_NEXT(last, inp_hash_wild) == NULL) {
|
||||
CK_LIST_INSERT_AFTER(last, inp, inp_hash_wild);
|
||||
|
||||
Reference in New Issue
Block a user