diff options
-rw-r--r-- | net/core/filter.c | 23 |
1 files changed, 11 insertions, 12 deletions
diff --git a/net/core/filter.c b/net/core/filter.c index 2be1830d3c35..54dddc92452d 100644 --- a/net/core/filter.c +++ b/net/core/filter.c | |||
@@ -398,7 +398,7 @@ int sk_chk_filter(struct sock_filter *filter, int flen) | |||
398 | */ | 398 | */ |
399 | int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | 399 | int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) |
400 | { | 400 | { |
401 | struct sk_filter *fp; | 401 | struct sk_filter *fp, *old_fp; |
402 | unsigned int fsize = sizeof(struct sock_filter) * fprog->len; | 402 | unsigned int fsize = sizeof(struct sock_filter) * fprog->len; |
403 | int err; | 403 | int err; |
404 | 404 | ||
@@ -418,19 +418,18 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) | |||
418 | fp->len = fprog->len; | 418 | fp->len = fprog->len; |
419 | 419 | ||
420 | err = sk_chk_filter(fp->insns, fp->len); | 420 | err = sk_chk_filter(fp->insns, fp->len); |
421 | if (!err) { | 421 | if (err) { |
422 | struct sk_filter *old_fp; | 422 | sk_filter_uncharge(sk, fp); |
423 | 423 | return err; | |
424 | rcu_read_lock_bh(); | ||
425 | old_fp = rcu_dereference(sk->sk_filter); | ||
426 | rcu_assign_pointer(sk->sk_filter, fp); | ||
427 | rcu_read_unlock_bh(); | ||
428 | fp = old_fp; | ||
429 | } | 424 | } |
430 | 425 | ||
431 | if (fp) | 426 | rcu_read_lock_bh(); |
432 | sk_filter_uncharge(sk, fp); | 427 | old_fp = rcu_dereference(sk->sk_filter); |
433 | return err; | 428 | rcu_assign_pointer(sk->sk_filter, fp); |
429 | rcu_read_unlock_bh(); | ||
430 | |||
431 | sk_filter_uncharge(sk, old_fp); | ||
432 | return 0; | ||
434 | } | 433 | } |
435 | 434 | ||
436 | int sk_detach_filter(struct sock *sk) | 435 | int sk_detach_filter(struct sock *sk) |