Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: sched: cls_bpf: Undo tcf_bind_filter in case of an error

If cls_bpf_offload errors out, we must also undo tcf_bind_filter that
was done before the error.

Fix that by calling tcf_unbind_filter in errout_parms.

Fixes: eadb41489fd2 ("net: cls_bpf: add support for marking filters as hardware-only")
Signed-off-by: Victor Nogueira <victor@mojatatu.com>
Acked-by: Jamal Hadi Salim <jhs@mojatatu.com>
Reviewed-by: Pedro Tammela <pctammela@mojatatu.com>
Reviewed-by: Simon Horman <simon.horman@corigine.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Victor Nogueira and committed by
David S. Miller
26a22194 e8d3d78c

+47 -52
+47 -52
net/sched/cls_bpf.c
··· 406 406 return 0; 407 407 } 408 408 409 - static int cls_bpf_set_parms(struct net *net, struct tcf_proto *tp, 410 - struct cls_bpf_prog *prog, unsigned long base, 411 - struct nlattr **tb, struct nlattr *est, u32 flags, 412 - struct netlink_ext_ack *extack) 413 - { 414 - bool is_bpf, is_ebpf, have_exts = false; 415 - u32 gen_flags = 0; 416 - int ret; 417 - 418 - is_bpf = tb[TCA_BPF_OPS_LEN] && tb[TCA_BPF_OPS]; 419 - is_ebpf = tb[TCA_BPF_FD]; 420 - if ((!is_bpf && !is_ebpf) || (is_bpf && is_ebpf)) 421 - return -EINVAL; 422 - 423 - ret = tcf_exts_validate(net, tp, tb, est, &prog->exts, flags, 424 - extack); 425 - if (ret < 0) 426 - return ret; 427 - 428 - if (tb[TCA_BPF_FLAGS]) { 429 - u32 bpf_flags = nla_get_u32(tb[TCA_BPF_FLAGS]); 430 - 431 - if (bpf_flags & ~TCA_BPF_FLAG_ACT_DIRECT) 432 - return -EINVAL; 433 - 434 - have_exts = bpf_flags & TCA_BPF_FLAG_ACT_DIRECT; 435 - } 436 - if (tb[TCA_BPF_FLAGS_GEN]) { 437 - gen_flags = nla_get_u32(tb[TCA_BPF_FLAGS_GEN]); 438 - if (gen_flags & ~CLS_BPF_SUPPORTED_GEN_FLAGS || 439 - !tc_flags_valid(gen_flags)) 440 - return -EINVAL; 441 - } 442 - 443 - prog->exts_integrated = have_exts; 444 - prog->gen_flags = gen_flags; 445 - 446 - ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) : 447 - cls_bpf_prog_from_efd(tb, prog, gen_flags, tp); 448 - if (ret < 0) 449 - return ret; 450 - 451 - if (tb[TCA_BPF_CLASSID]) { 452 - prog->res.classid = nla_get_u32(tb[TCA_BPF_CLASSID]); 453 - tcf_bind_filter(tp, &prog->res, base); 454 - } 455 - 456 - return 0; 457 - } 458 - 459 409 static int cls_bpf_change(struct net *net, struct sk_buff *in_skb, 460 410 struct tcf_proto *tp, unsigned long base, 461 411 u32 handle, struct nlattr **tca, ··· 413 463 struct netlink_ext_ack *extack) 414 464 { 415 465 struct cls_bpf_head *head = rtnl_dereference(tp->root); 466 + bool is_bpf, is_ebpf, have_exts = false; 416 467 struct cls_bpf_prog *oldprog = *arg; 417 468 struct nlattr *tb[TCA_BPF_MAX + 1]; 469 + bool bound_to_filter = false; 418 470 struct cls_bpf_prog *prog; 471 + u32 gen_flags = 0; 419 472 int ret; 420 473 421 474 if (tca[TCA_OPTIONS] == NULL) ··· 457 504 goto errout; 458 505 prog->handle = handle; 459 506 460 - ret = cls_bpf_set_parms(net, tp, prog, base, tb, tca[TCA_RATE], flags, 461 - extack); 507 + is_bpf = tb[TCA_BPF_OPS_LEN] && tb[TCA_BPF_OPS]; 508 + is_ebpf = tb[TCA_BPF_FD]; 509 + if ((!is_bpf && !is_ebpf) || (is_bpf && is_ebpf)) { 510 + ret = -EINVAL; 511 + goto errout_idr; 512 + } 513 + 514 + ret = tcf_exts_validate(net, tp, tb, tca[TCA_RATE], &prog->exts, 515 + flags, extack); 462 516 if (ret < 0) 463 517 goto errout_idr; 518 + 519 + if (tb[TCA_BPF_FLAGS]) { 520 + u32 bpf_flags = nla_get_u32(tb[TCA_BPF_FLAGS]); 521 + 522 + if (bpf_flags & ~TCA_BPF_FLAG_ACT_DIRECT) { 523 + ret = -EINVAL; 524 + goto errout_idr; 525 + } 526 + 527 + have_exts = bpf_flags & TCA_BPF_FLAG_ACT_DIRECT; 528 + } 529 + if (tb[TCA_BPF_FLAGS_GEN]) { 530 + gen_flags = nla_get_u32(tb[TCA_BPF_FLAGS_GEN]); 531 + if (gen_flags & ~CLS_BPF_SUPPORTED_GEN_FLAGS || 532 + !tc_flags_valid(gen_flags)) { 533 + ret = -EINVAL; 534 + goto errout_idr; 535 + } 536 + } 537 + 538 + prog->exts_integrated = have_exts; 539 + prog->gen_flags = gen_flags; 540 + 541 + ret = is_bpf ? cls_bpf_prog_from_ops(tb, prog) : 542 + cls_bpf_prog_from_efd(tb, prog, gen_flags, tp); 543 + if (ret < 0) 544 + goto errout_idr; 545 + 546 + if (tb[TCA_BPF_CLASSID]) { 547 + prog->res.classid = nla_get_u32(tb[TCA_BPF_CLASSID]); 548 + tcf_bind_filter(tp, &prog->res, base); 549 + bound_to_filter = true; 550 + } 464 551 465 552 ret = cls_bpf_offload(tp, prog, oldprog, extack); 466 553 if (ret) ··· 523 530 return 0; 524 531 525 532 errout_parms: 533 + if (bound_to_filter) 534 + tcf_unbind_filter(tp, &prog->res); 526 535 cls_bpf_free_parms(prog); 527 536 errout_idr: 528 537 if (!oldprog)