netfilter: xtables: fix reentrancy

commit f3c5c1bfd4308 (make ip_tables reentrant) introduced a race in
handling the stackptr restore, at the end of ipt_do_table()

We should do it before the call to xt_info_rdunlock_bh(), or we allow
cpu preemption and another cpu overwrites stackptr of original one.

A second fix is to change the underflow test to check the origptr value
instead of 0 to detect underflow, or else we allow a jump from different
hooks.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Jan Engelhardt <jengelh@medozas.de>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by Eric Dumazet and committed by Patrick McHardy db856674 5c1aba46

+4 -4
+2 -2
net/ipv4/netfilter/ip_tables.c
··· 387 verdict = (unsigned)(-v) - 1; 388 break; 389 } 390 - if (*stackptr == 0) { 391 e = get_entry(table_base, 392 private->underflow[hook]); 393 pr_debug("Underflow (this is normal) " ··· 427 /* Verdict */ 428 break; 429 } while (!acpar.hotdrop); 430 - xt_info_rdunlock_bh(); 431 pr_debug("Exiting %s; resetting sp from %u to %u\n", 432 __func__, *stackptr, origptr); 433 *stackptr = origptr; 434 #ifdef DEBUG_ALLOW_ALL 435 return NF_ACCEPT; 436 #else
··· 387 verdict = (unsigned)(-v) - 1; 388 break; 389 } 390 + if (*stackptr <= origptr) { 391 e = get_entry(table_base, 392 private->underflow[hook]); 393 pr_debug("Underflow (this is normal) " ··· 427 /* Verdict */ 428 break; 429 } while (!acpar.hotdrop); 430 pr_debug("Exiting %s; resetting sp from %u to %u\n", 431 __func__, *stackptr, origptr); 432 *stackptr = origptr; 433 + xt_info_rdunlock_bh(); 434 #ifdef DEBUG_ALLOW_ALL 435 return NF_ACCEPT; 436 #else
+2 -2
net/ipv6/netfilter/ip6_tables.c
··· 410 verdict = (unsigned)(-v) - 1; 411 break; 412 } 413 - if (*stackptr == 0) 414 e = get_entry(table_base, 415 private->underflow[hook]); 416 else ··· 441 break; 442 } while (!acpar.hotdrop); 443 444 - xt_info_rdunlock_bh(); 445 *stackptr = origptr; 446 447 #ifdef DEBUG_ALLOW_ALL 448 return NF_ACCEPT;
··· 410 verdict = (unsigned)(-v) - 1; 411 break; 412 } 413 + if (*stackptr <= origptr) 414 e = get_entry(table_base, 415 private->underflow[hook]); 416 else ··· 441 break; 442 } while (!acpar.hotdrop); 443 444 *stackptr = origptr; 445 + xt_info_rdunlock_bh(); 446 447 #ifdef DEBUG_ALLOW_ALL 448 return NF_ACCEPT;