Re: [PATCH net-next 1/1] net sched actions: fix invalid pointer dereferencing if skbedit flags missing

2018-05-10 Thread Cong Wang
On Wed, May 9, 2018 at 2:18 PM, Roman Mashak  wrote:
> The caller calls action's ->init() and passes pointer to "struct tc_action 
> *a",
> which later may initialized to point at the existing action, otherwise
> "struct tc_action *a" is still invalid, and therefore dereferencing it is 
> error.

So technically we just need to check if(exists) before calling
tcf_idr_release(), right?


>
> So checking flags should be done as early as possible, before idr lookups.

In theory, this could break the case of binding an existing action.
But in practice it seems nonsense to pass invalid flags in this case
either, so probably this is okay.

BTW, this should be a candidate for -net and possibly -stable too.


[PATCH net-next 1/1] net sched actions: fix invalid pointer dereferencing if skbedit flags missing

2018-05-09 Thread Roman Mashak
When application fails to pass flags in netlink TLV for a new skbedit action,
the kernel results in the following oops:

[8.307732] BUG: unable to handle kernel paging request at 00021130
[8.309167] PGD 8000193d1067 P4D 8000193d1067 PUD 180e0067 PMD 0 
[8.310595] Oops:  [#1] SMP PTI
[8.311334] Modules linked in: kvm_intel kvm irqbypass crct10dif_pclmul 
crc32_pclmul ghash_clmulni_intel pcbc aesni_intel aes_x86_64 crypto_simd cryptd 
glue_helper serio_raw
[8.314190] CPU: 1 PID: 397 Comm: tc Not tainted 4.17.0-rc3+ #357
[8.315252] RIP: 0010:__tcf_idr_release+0x33/0x140
[8.316203] RSP: 0018:a0718038f840 EFLAGS: 00010246
[8.317123] RAX: 0001 RBX: 00021100 RCX: 
[8.319831] RDX:  RSI:  RDI: 00021100
[8.321181] RBP:  R08: 0004adf8 R09: 0122
[8.322645] R10:  R11: 9e5b01ed R12: 
[8.324157] R13: 9e0d3cc0 R14:  R15: 
[8.325590] FS:  7f591292e700() GS:8fcf5bc4() 
knlGS:
[8.327001] CS:  0010 DS:  ES:  CR0: 80050033
[8.327987] CR2: 00021130 CR3: 180e6004 CR4: 001606a0
[8.329289] Call Trace:
[8.329735]  tcf_skbedit_init+0xa7/0xb0
[8.330423]  tcf_action_init_1+0x362/0x410
[8.331139]  ? try_to_wake_up+0x44/0x430
[8.331817]  tcf_action_init+0x103/0x190
[8.332511]  tc_ctl_action+0x11a/0x220
[8.333174]  rtnetlink_rcv_msg+0x23d/0x2e0
[8.333902]  ? _cond_resched+0x16/0x40
[8.334569]  ? __kmalloc_node_track_caller+0x5b/0x2c0
[8.335440]  ? rtnl_calcit.isra.31+0xf0/0xf0
[8.336178]  netlink_rcv_skb+0xdb/0x110
[8.336855]  netlink_unicast+0x167/0x220
[8.337550]  netlink_sendmsg+0x2a7/0x390
[8.338258]  sock_sendmsg+0x30/0x40
[8.338865]  ___sys_sendmsg+0x2c5/0x2e0
[8.339531]  ? pagecache_get_page+0x27/0x210
[8.340271]  ? filemap_fault+0xa2/0x630
[8.340943]  ? page_add_file_rmap+0x108/0x200
[8.341732]  ? alloc_set_pte+0x2aa/0x530
[8.342573]  ? finish_fault+0x4e/0x70
[8.343332]  ? __handle_mm_fault+0xbc1/0x10d0
[8.344337]  ? __sys_sendmsg+0x53/0x80
[8.345040]  __sys_sendmsg+0x53/0x80
[8.345678]  do_syscall_64+0x4f/0x100
[8.346339]  entry_SYSCALL_64_after_hwframe+0x44/0xa9
[8.347206] RIP: 0033:0x7f591191da67
[8.347831] RSP: 002b:7fff745abd48 EFLAGS: 0246 ORIG_RAX: 
002e
[8.349179] RAX: ffda RBX: 7fff745abe70 RCX: 7f591191da67
[8.350431] RDX:  RSI: 7fff745abdc0 RDI: 0003
[8.351659] RBP: 5af35251 R08: 0001 R09: 
[8.352922] R10: 05f1 R11: 0246 R12: 
[8.354183] R13: 7fff745afed0 R14: 0001 R15: 006767c0
[8.355400] Code: 41 89 d4 53 89 f5 48 89 fb e8 aa 20 fd ff 85 c0 0f 84 ed 00
00 00 48 85 db 0f 84 cf 00 00 00 40 84 ed 0f 85 cd 00 00 00 45 84 e4 <8b> 53 30
74 0d 85 d2 b8 ff ff ff ff 0f 8f b3 00 00 00 8b 43 2c 
[8.358699] RIP: __tcf_idr_release+0x33/0x140 RSP: a0718038f840
[8.359770] CR2: 00021130
[8.360438] ---[ end trace 60c66be45dfc14f0 ]---

The caller calls action's ->init() and passes pointer to "struct tc_action *a",
which later may initialized to point at the existing action, otherwise
"struct tc_action *a" is still invalid, and therefore dereferencing it is error.

So checking flags should be done as early as possible, before idr lookups.

Signed-off-by: Roman Mashak 
---
 net/sched/act_skbedit.c | 8 +++-
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c
index ddf69fc01bdf..6c88037faf51 100644
--- a/net/sched/act_skbedit.c
+++ b/net/sched/act_skbedit.c
@@ -114,17 +114,15 @@ static int tcf_skbedit_init(struct net *net, struct 
nlattr *nla,
mask = nla_data(tb[TCA_SKBEDIT_MASK]);
}
 
+   if (!flags)
+   return -EINVAL;
+
parm = nla_data(tb[TCA_SKBEDIT_PARMS]);
 
exists = tcf_idr_check(tn, parm->index, a, bind);
if (exists && bind)
return 0;
 
-   if (!flags) {
-   tcf_idr_release(*a, bind);
-   return -EINVAL;
-   }
-
if (!exists) {
ret = tcf_idr_create(tn, parm->index, est, a,
 &act_skbedit_ops, bind, false);
-- 
2.7.4