mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-07 07:08:07 +00:00
[IPV4]: Fix refcount damaging in net/ipv4/route.c
One such place that can damage the dst refcnts is route.c with CONFIG_IP_ROUTE_MULTIPATH_CACHED enabled, i don't see the user's .config. In this new code i see that rt_intern_hash is called before dst->refcnt is set to 1, dst is the 2nd arg to rt_intern_hash. Arg 2 of rt_intern_hash must come with refcnt 1 as it is added to table or dropped depending on error/add/update. One such example is ip_mkroute_input where __mkroute_input return rth with refcnt 0 which is provided to rt_intern_hash. ip_mkroute_output looks like a 2nd such place. Appending untested patch for comments and review. The idea is to put previous reference as we are going to return next result/error. Signed-off-by: Julian Anastasov <ja@ssi.bg> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c921e4c4db
commit
ce723d8e04
1 changed files with 14 additions and 15 deletions
|
@ -1760,6 +1760,7 @@ static inline int __mkroute_input(struct sk_buff *skb,
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atomic_set(&rth->u.dst.__refcnt, 1);
|
||||||
rth->u.dst.flags= DST_HOST;
|
rth->u.dst.flags= DST_HOST;
|
||||||
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
|
||||||
if (res->fi->fib_nhs > 1)
|
if (res->fi->fib_nhs > 1)
|
||||||
|
@ -1820,7 +1821,6 @@ static inline int ip_mkroute_input_def(struct sk_buff *skb,
|
||||||
err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);
|
err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
atomic_set(&rth->u.dst.__refcnt, 1);
|
|
||||||
|
|
||||||
/* put it into the cache */
|
/* put it into the cache */
|
||||||
hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
|
hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
|
||||||
|
@ -1834,8 +1834,8 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
|
||||||
u32 daddr, u32 saddr, u32 tos)
|
u32 daddr, u32 saddr, u32 tos)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
|
||||||
struct rtable* rth = NULL;
|
struct rtable* rth = NULL, *rtres;
|
||||||
unsigned char hop, hopcount, lasthop;
|
unsigned char hop, hopcount;
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
unsigned int hash;
|
unsigned int hash;
|
||||||
|
|
||||||
|
@ -1844,8 +1844,6 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
|
||||||
else
|
else
|
||||||
hopcount = 1;
|
hopcount = 1;
|
||||||
|
|
||||||
lasthop = hopcount - 1;
|
|
||||||
|
|
||||||
/* distinguish between multipath and singlepath */
|
/* distinguish between multipath and singlepath */
|
||||||
if (hopcount < 2)
|
if (hopcount < 2)
|
||||||
return ip_mkroute_input_def(skb, res, fl, in_dev, daddr,
|
return ip_mkroute_input_def(skb, res, fl, in_dev, daddr,
|
||||||
|
@ -1855,6 +1853,10 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
|
||||||
for (hop = 0; hop < hopcount; hop++) {
|
for (hop = 0; hop < hopcount; hop++) {
|
||||||
res->nh_sel = hop;
|
res->nh_sel = hop;
|
||||||
|
|
||||||
|
/* put reference to previous result */
|
||||||
|
if (hop)
|
||||||
|
ip_rt_put(rtres);
|
||||||
|
|
||||||
/* create a routing cache entry */
|
/* create a routing cache entry */
|
||||||
err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos,
|
err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos,
|
||||||
&rth);
|
&rth);
|
||||||
|
@ -1863,7 +1865,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
|
||||||
|
|
||||||
/* put it into the cache */
|
/* put it into the cache */
|
||||||
hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
|
hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
|
||||||
err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
|
err = rt_intern_hash(hash, rth, &rtres);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -1873,13 +1875,8 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
|
||||||
FIB_RES_NETMASK(*res),
|
FIB_RES_NETMASK(*res),
|
||||||
res->prefixlen,
|
res->prefixlen,
|
||||||
&FIB_RES_NH(*res));
|
&FIB_RES_NH(*res));
|
||||||
|
|
||||||
/* only for the last hop the reference count is handled
|
|
||||||
* outside
|
|
||||||
*/
|
|
||||||
if (hop == lasthop)
|
|
||||||
atomic_set(&(skb->dst->__refcnt), 1);
|
|
||||||
}
|
}
|
||||||
|
skb->dst = &rtres->u.dst;
|
||||||
return err;
|
return err;
|
||||||
#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
|
#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
|
||||||
return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos);
|
return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos);
|
||||||
|
@ -2208,6 +2205,7 @@ static inline int __mkroute_output(struct rtable **result,
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
atomic_set(&rth->u.dst.__refcnt, 1);
|
||||||
rth->u.dst.flags= DST_HOST;
|
rth->u.dst.flags= DST_HOST;
|
||||||
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
|
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
|
||||||
if (res->fi) {
|
if (res->fi) {
|
||||||
|
@ -2290,8 +2288,6 @@ static inline int ip_mkroute_output_def(struct rtable **rp,
|
||||||
if (err == 0) {
|
if (err == 0) {
|
||||||
u32 tos = RT_FL_TOS(oldflp);
|
u32 tos = RT_FL_TOS(oldflp);
|
||||||
|
|
||||||
atomic_set(&rth->u.dst.__refcnt, 1);
|
|
||||||
|
|
||||||
hash = rt_hash_code(oldflp->fl4_dst,
|
hash = rt_hash_code(oldflp->fl4_dst,
|
||||||
oldflp->fl4_src ^ (oldflp->oif << 5), tos);
|
oldflp->fl4_src ^ (oldflp->oif << 5), tos);
|
||||||
err = rt_intern_hash(hash, rth, rp);
|
err = rt_intern_hash(hash, rth, rp);
|
||||||
|
@ -2326,6 +2322,10 @@ static inline int ip_mkroute_output(struct rtable** rp,
|
||||||
dev2nexthop = FIB_RES_DEV(*res);
|
dev2nexthop = FIB_RES_DEV(*res);
|
||||||
dev_hold(dev2nexthop);
|
dev_hold(dev2nexthop);
|
||||||
|
|
||||||
|
/* put reference to previous result */
|
||||||
|
if (hop)
|
||||||
|
ip_rt_put(*rp);
|
||||||
|
|
||||||
err = __mkroute_output(&rth, res, fl, oldflp,
|
err = __mkroute_output(&rth, res, fl, oldflp,
|
||||||
dev2nexthop, flags);
|
dev2nexthop, flags);
|
||||||
|
|
||||||
|
@ -2350,7 +2350,6 @@ static inline int ip_mkroute_output(struct rtable** rp,
|
||||||
if (err != 0)
|
if (err != 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
atomic_set(&(*rp)->u.dst.__refcnt, 1);
|
|
||||||
return err;
|
return err;
|
||||||
} else {
|
} else {
|
||||||
return ip_mkroute_output_def(rp, res, fl, oldflp, dev_out,
|
return ip_mkroute_output_def(rp, res, fl, oldflp, dev_out,
|
||||||
|
|
Loading…
Add table
Reference in a new issue