diff options
author | Reshetova, Elena <elena.reshetova@intel.com> | 2017-06-30 06:07:57 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-07-01 10:39:07 -0400 |
commit | 53869cebce4bc53f71a080e7830600d4ae1ab712 (patch) | |
tree | c99b8ea34f0b909e5db784b7426e1afcb21aeabf | |
parent | 6343944bc1050dcec7c959f484ee0fb6928db3be (diff) |
net: convert nf_bridge_info.use from atomic_t to refcount_t
refcount_t type and corresponding API should be
used instead of atomic_t when the variable is used as
a reference counter. This allows to avoid accidental
refcounter overflows that might lead to use-after-free
situations.
Signed-off-by: Elena Reshetova <elena.reshetova@intel.com>
Signed-off-by: Hans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: Kees Cook <keescook@chromium.org>
Signed-off-by: David Windsor <dwindsor@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/skbuff.h | 6 | ||||
-rw-r--r-- | include/net/netfilter/br_netfilter.h | 2 | ||||
-rw-r--r-- | net/bridge/br_netfilter_hooks.c | 4 |
3 files changed, 6 insertions, 6 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index a17e235639ae..005793e01bd2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -252,7 +252,7 @@ struct nf_conntrack { | |||
252 | 252 | ||
253 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) | 253 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
254 | struct nf_bridge_info { | 254 | struct nf_bridge_info { |
255 | atomic_t use; | 255 | refcount_t use; |
256 | enum { | 256 | enum { |
257 | BRNF_PROTO_UNCHANGED, | 257 | BRNF_PROTO_UNCHANGED, |
258 | BRNF_PROTO_8021Q, | 258 | BRNF_PROTO_8021Q, |
@@ -3589,13 +3589,13 @@ static inline void nf_conntrack_get(struct nf_conntrack *nfct) | |||
3589 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) | 3589 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
3590 | static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) | 3590 | static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) |
3591 | { | 3591 | { |
3592 | if (nf_bridge && atomic_dec_and_test(&nf_bridge->use)) | 3592 | if (nf_bridge && refcount_dec_and_test(&nf_bridge->use)) |
3593 | kfree(nf_bridge); | 3593 | kfree(nf_bridge); |
3594 | } | 3594 | } |
3595 | static inline void nf_bridge_get(struct nf_bridge_info *nf_bridge) | 3595 | static inline void nf_bridge_get(struct nf_bridge_info *nf_bridge) |
3596 | { | 3596 | { |
3597 | if (nf_bridge) | 3597 | if (nf_bridge) |
3598 | atomic_inc(&nf_bridge->use); | 3598 | refcount_inc(&nf_bridge->use); |
3599 | } | 3599 | } |
3600 | #endif /* CONFIG_BRIDGE_NETFILTER */ | 3600 | #endif /* CONFIG_BRIDGE_NETFILTER */ |
3601 | static inline void nf_reset(struct sk_buff *skb) | 3601 | static inline void nf_reset(struct sk_buff *skb) |
diff --git a/include/net/netfilter/br_netfilter.h b/include/net/netfilter/br_netfilter.h index 0b0c35c37125..925524ede6c8 100644 --- a/include/net/netfilter/br_netfilter.h +++ b/include/net/netfilter/br_netfilter.h | |||
@@ -8,7 +8,7 @@ static inline struct nf_bridge_info *nf_bridge_alloc(struct sk_buff *skb) | |||
8 | skb->nf_bridge = kzalloc(sizeof(struct nf_bridge_info), GFP_ATOMIC); | 8 | skb->nf_bridge = kzalloc(sizeof(struct nf_bridge_info), GFP_ATOMIC); |
9 | 9 | ||
10 | if (likely(skb->nf_bridge)) | 10 | if (likely(skb->nf_bridge)) |
11 | atomic_set(&(skb->nf_bridge->use), 1); | 11 | refcount_set(&(skb->nf_bridge->use), 1); |
12 | 12 | ||
13 | return skb->nf_bridge; | 13 | return skb->nf_bridge; |
14 | } | 14 | } |
diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c index 067cf0313449..2261e5194c82 100644 --- a/net/bridge/br_netfilter_hooks.c +++ b/net/bridge/br_netfilter_hooks.c | |||
@@ -149,12 +149,12 @@ static inline struct nf_bridge_info *nf_bridge_unshare(struct sk_buff *skb) | |||
149 | { | 149 | { |
150 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; | 150 | struct nf_bridge_info *nf_bridge = skb->nf_bridge; |
151 | 151 | ||
152 | if (atomic_read(&nf_bridge->use) > 1) { | 152 | if (refcount_read(&nf_bridge->use) > 1) { |
153 | struct nf_bridge_info *tmp = nf_bridge_alloc(skb); | 153 | struct nf_bridge_info *tmp = nf_bridge_alloc(skb); |
154 | 154 | ||
155 | if (tmp) { | 155 | if (tmp) { |
156 | memcpy(tmp, nf_bridge, sizeof(struct nf_bridge_info)); | 156 | memcpy(tmp, nf_bridge, sizeof(struct nf_bridge_info)); |
157 | atomic_set(&tmp->use, 1); | 157 | refcount_set(&tmp->use, 1); |
158 | } | 158 | } |
159 | nf_bridge_put(nf_bridge); | 159 | nf_bridge_put(nf_bridge); |
160 | nf_bridge = tmp; | 160 | nf_bridge = tmp; |