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