mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-22 06:32:08 +00:00
Merge branch 'ipv6-fib6_ref-conversion-to-refcount_t'
Eric Dumazet says: ==================== ipv6: fib6_ref conversion to refcount_t We are chasing use-after-free in IPv6 that could have their origin in fib6_ref 0 -> 1 transitions. This patch series should help finding the root causes if these illegal transitions ever happen. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
6b18bdfdba
3 changed files with 16 additions and 19 deletions
|
@ -146,7 +146,7 @@ struct fib6_info {
|
||||||
struct list_head fib6_siblings;
|
struct list_head fib6_siblings;
|
||||||
unsigned int fib6_nsiblings;
|
unsigned int fib6_nsiblings;
|
||||||
|
|
||||||
atomic_t fib6_ref;
|
refcount_t fib6_ref;
|
||||||
unsigned long expires;
|
unsigned long expires;
|
||||||
struct dst_metrics *fib6_metrics;
|
struct dst_metrics *fib6_metrics;
|
||||||
#define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1]
|
#define fib6_pmtu fib6_metrics->metrics[RTAX_MTU-1]
|
||||||
|
@ -284,17 +284,17 @@ void fib6_info_destroy_rcu(struct rcu_head *head);
|
||||||
|
|
||||||
static inline void fib6_info_hold(struct fib6_info *f6i)
|
static inline void fib6_info_hold(struct fib6_info *f6i)
|
||||||
{
|
{
|
||||||
atomic_inc(&f6i->fib6_ref);
|
refcount_inc(&f6i->fib6_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool fib6_info_hold_safe(struct fib6_info *f6i)
|
static inline bool fib6_info_hold_safe(struct fib6_info *f6i)
|
||||||
{
|
{
|
||||||
return atomic_inc_not_zero(&f6i->fib6_ref);
|
return refcount_inc_not_zero(&f6i->fib6_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void fib6_info_release(struct fib6_info *f6i)
|
static inline void fib6_info_release(struct fib6_info *f6i)
|
||||||
{
|
{
|
||||||
if (f6i && atomic_dec_and_test(&f6i->fib6_ref))
|
if (f6i && refcount_dec_and_test(&f6i->fib6_ref))
|
||||||
call_rcu(&f6i->rcu, fib6_info_destroy_rcu);
|
call_rcu(&f6i->rcu, fib6_info_destroy_rcu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,7 +162,7 @@ struct fib6_info *fib6_info_alloc(gfp_t gfp_flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_LIST_HEAD(&f6i->fib6_siblings);
|
INIT_LIST_HEAD(&f6i->fib6_siblings);
|
||||||
atomic_inc(&f6i->fib6_ref);
|
refcount_set(&f6i->fib6_ref, 1);
|
||||||
|
|
||||||
return f6i;
|
return f6i;
|
||||||
}
|
}
|
||||||
|
@ -175,10 +175,7 @@ void fib6_info_destroy_rcu(struct rcu_head *head)
|
||||||
WARN_ON(f6i->fib6_node);
|
WARN_ON(f6i->fib6_node);
|
||||||
|
|
||||||
bucket = rcu_dereference_protected(f6i->rt6i_exception_bucket, 1);
|
bucket = rcu_dereference_protected(f6i->rt6i_exception_bucket, 1);
|
||||||
if (bucket) {
|
|
||||||
f6i->rt6i_exception_bucket = NULL;
|
|
||||||
kfree(bucket);
|
kfree(bucket);
|
||||||
}
|
|
||||||
|
|
||||||
if (f6i->rt6i_pcpu) {
|
if (f6i->rt6i_pcpu) {
|
||||||
int cpu;
|
int cpu;
|
||||||
|
@ -849,8 +846,8 @@ insert_above:
|
||||||
|
|
||||||
RCU_INIT_POINTER(in->parent, pn);
|
RCU_INIT_POINTER(in->parent, pn);
|
||||||
in->leaf = fn->leaf;
|
in->leaf = fn->leaf;
|
||||||
atomic_inc(&rcu_dereference_protected(in->leaf,
|
fib6_info_hold(rcu_dereference_protected(in->leaf,
|
||||||
lockdep_is_held(&table->tb6_lock))->fib6_ref);
|
lockdep_is_held(&table->tb6_lock)));
|
||||||
|
|
||||||
/* update parent pointer */
|
/* update parent pointer */
|
||||||
if (dir)
|
if (dir)
|
||||||
|
@ -932,7 +929,7 @@ static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn,
|
||||||
{
|
{
|
||||||
struct fib6_table *table = rt->fib6_table;
|
struct fib6_table *table = rt->fib6_table;
|
||||||
|
|
||||||
if (atomic_read(&rt->fib6_ref) != 1) {
|
if (refcount_read(&rt->fib6_ref) != 1) {
|
||||||
/* This route is used as dummy address holder in some split
|
/* This route is used as dummy address holder in some split
|
||||||
* nodes. It is not leaked, but it still holds other resources,
|
* nodes. It is not leaked, but it still holds other resources,
|
||||||
* which must be released in time. So, scan ascendant nodes
|
* which must be released in time. So, scan ascendant nodes
|
||||||
|
@ -945,7 +942,7 @@ static void fib6_purge_rt(struct fib6_info *rt, struct fib6_node *fn,
|
||||||
struct fib6_info *new_leaf;
|
struct fib6_info *new_leaf;
|
||||||
if (!(fn->fn_flags & RTN_RTINFO) && leaf == rt) {
|
if (!(fn->fn_flags & RTN_RTINFO) && leaf == rt) {
|
||||||
new_leaf = fib6_find_prefix(net, table, fn);
|
new_leaf = fib6_find_prefix(net, table, fn);
|
||||||
atomic_inc(&new_leaf->fib6_ref);
|
fib6_info_hold(new_leaf);
|
||||||
|
|
||||||
rcu_assign_pointer(fn->leaf, new_leaf);
|
rcu_assign_pointer(fn->leaf, new_leaf);
|
||||||
fib6_info_release(rt);
|
fib6_info_release(rt);
|
||||||
|
@ -1111,7 +1108,7 @@ add:
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
rcu_assign_pointer(rt->fib6_next, iter);
|
rcu_assign_pointer(rt->fib6_next, iter);
|
||||||
atomic_inc(&rt->fib6_ref);
|
fib6_info_hold(rt);
|
||||||
rcu_assign_pointer(rt->fib6_node, fn);
|
rcu_assign_pointer(rt->fib6_node, fn);
|
||||||
rcu_assign_pointer(*ins, rt);
|
rcu_assign_pointer(*ins, rt);
|
||||||
if (!info->skip_notify)
|
if (!info->skip_notify)
|
||||||
|
@ -1139,7 +1136,7 @@ add:
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
atomic_inc(&rt->fib6_ref);
|
fib6_info_hold(rt);
|
||||||
rcu_assign_pointer(rt->fib6_node, fn);
|
rcu_assign_pointer(rt->fib6_node, fn);
|
||||||
rt->fib6_next = iter->fib6_next;
|
rt->fib6_next = iter->fib6_next;
|
||||||
rcu_assign_pointer(*ins, rt);
|
rcu_assign_pointer(*ins, rt);
|
||||||
|
@ -1281,7 +1278,7 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,
|
||||||
if (!sfn)
|
if (!sfn)
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
||||||
atomic_inc(&info->nl_net->ipv6.fib6_null_entry->fib6_ref);
|
fib6_info_hold(info->nl_net->ipv6.fib6_null_entry);
|
||||||
rcu_assign_pointer(sfn->leaf,
|
rcu_assign_pointer(sfn->leaf,
|
||||||
info->nl_net->ipv6.fib6_null_entry);
|
info->nl_net->ipv6.fib6_null_entry);
|
||||||
sfn->fn_flags = RTN_ROOT;
|
sfn->fn_flags = RTN_ROOT;
|
||||||
|
@ -1324,7 +1321,7 @@ int fib6_add(struct fib6_node *root, struct fib6_info *rt,
|
||||||
rcu_assign_pointer(fn->leaf,
|
rcu_assign_pointer(fn->leaf,
|
||||||
info->nl_net->ipv6.fib6_null_entry);
|
info->nl_net->ipv6.fib6_null_entry);
|
||||||
} else {
|
} else {
|
||||||
atomic_inc(&rt->fib6_ref);
|
fib6_info_hold(rt);
|
||||||
rcu_assign_pointer(fn->leaf, rt);
|
rcu_assign_pointer(fn->leaf, rt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2314,7 +2311,7 @@ static int ipv6_route_seq_show(struct seq_file *seq, void *v)
|
||||||
|
|
||||||
dev = rt->fib6_nh.fib_nh_dev;
|
dev = rt->fib6_nh.fib_nh_dev;
|
||||||
seq_printf(seq, " %08x %08x %08x %08x %8s\n",
|
seq_printf(seq, " %08x %08x %08x %08x %8s\n",
|
||||||
rt->fib6_metric, atomic_read(&rt->fib6_ref), 0,
|
rt->fib6_metric, refcount_read(&rt->fib6_ref), 0,
|
||||||
flags, dev ? dev->name : "");
|
flags, dev ? dev->name : "");
|
||||||
iter->w.leaf = NULL;
|
iter->w.leaf = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -296,7 +296,7 @@ static const struct fib6_info fib6_null_entry_template = {
|
||||||
.fib6_flags = (RTF_REJECT | RTF_NONEXTHOP),
|
.fib6_flags = (RTF_REJECT | RTF_NONEXTHOP),
|
||||||
.fib6_protocol = RTPROT_KERNEL,
|
.fib6_protocol = RTPROT_KERNEL,
|
||||||
.fib6_metric = ~(u32)0,
|
.fib6_metric = ~(u32)0,
|
||||||
.fib6_ref = ATOMIC_INIT(1),
|
.fib6_ref = REFCOUNT_INIT(1),
|
||||||
.fib6_type = RTN_UNREACHABLE,
|
.fib6_type = RTN_UNREACHABLE,
|
||||||
.fib6_metrics = (struct dst_metrics *)&dst_default_metrics,
|
.fib6_metrics = (struct dst_metrics *)&dst_default_metrics,
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue