aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJulian Anastasov <ja@ssi.bg>2005-09-08 16:34:47 -0400
committerDavid S. Miller <davem@davemloft.net>2005-09-08 16:34:47 -0400
commitce723d8e048ef98ea64d12379e3921c933f5b3e0 (patch)
tree368e85ac0014d203bba15bb8777ffbd94dc2d2e6
parentc921e4c4dbb043f9435414c4e661e7f0a783053d (diff)
[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>
-rw-r--r--net/ipv4/route.c29
1 files changed, 14 insertions, 15 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 8c0b14e3beec..8549f26e2495 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1760,6 +1760,7 @@ static inline int __mkroute_input(struct sk_buff *skb,
1760 goto cleanup; 1760 goto cleanup;
1761 } 1761 }
1762 1762
1763 atomic_set(&rth->u.dst.__refcnt, 1);
1763 rth->u.dst.flags= DST_HOST; 1764 rth->u.dst.flags= DST_HOST;
1764#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED 1765#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
1765 if (res->fi->fib_nhs > 1) 1766 if (res->fi->fib_nhs > 1)
@@ -1820,7 +1821,6 @@ static inline int ip_mkroute_input_def(struct sk_buff *skb,
1820 err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth); 1821 err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, &rth);
1821 if (err) 1822 if (err)
1822 return err; 1823 return err;
1823 atomic_set(&rth->u.dst.__refcnt, 1);
1824 1824
1825 /* put it into the cache */ 1825 /* put it into the cache */
1826 hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos); 1826 hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
@@ -1834,8 +1834,8 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
1834 u32 daddr, u32 saddr, u32 tos) 1834 u32 daddr, u32 saddr, u32 tos)
1835{ 1835{
1836#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED 1836#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
1837 struct rtable* rth = NULL; 1837 struct rtable* rth = NULL, *rtres;
1838 unsigned char hop, hopcount, lasthop; 1838 unsigned char hop, hopcount;
1839 int err = -EINVAL; 1839 int err = -EINVAL;
1840 unsigned int hash; 1840 unsigned int hash;
1841 1841
@@ -1844,8 +1844,6 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
1844 else 1844 else
1845 hopcount = 1; 1845 hopcount = 1;
1846 1846
1847 lasthop = hopcount - 1;
1848
1849 /* distinguish between multipath and singlepath */ 1847 /* distinguish between multipath and singlepath */
1850 if (hopcount < 2) 1848 if (hopcount < 2)
1851 return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, 1849 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,
1855 for (hop = 0; hop < hopcount; hop++) { 1853 for (hop = 0; hop < hopcount; hop++) {
1856 res->nh_sel = hop; 1854 res->nh_sel = hop;
1857 1855
1856 /* put reference to previous result */
1857 if (hop)
1858 ip_rt_put(rtres);
1859
1858 /* create a routing cache entry */ 1860 /* create a routing cache entry */
1859 err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos, 1861 err = __mkroute_input(skb, res, in_dev, daddr, saddr, tos,
1860 &rth); 1862 &rth);
@@ -1863,7 +1865,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
1863 1865
1864 /* put it into the cache */ 1866 /* put it into the cache */
1865 hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos); 1867 hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5), tos);
1866 err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst); 1868 err = rt_intern_hash(hash, rth, &rtres);
1867 if (err) 1869 if (err)
1868 return err; 1870 return err;
1869 1871
@@ -1873,13 +1875,8 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
1873 FIB_RES_NETMASK(*res), 1875 FIB_RES_NETMASK(*res),
1874 res->prefixlen, 1876 res->prefixlen,
1875 &FIB_RES_NH(*res)); 1877 &FIB_RES_NH(*res));
1876
1877 /* only for the last hop the reference count is handled
1878 * outside
1879 */
1880 if (hop == lasthop)
1881 atomic_set(&(skb->dst->__refcnt), 1);
1882 } 1878 }
1879 skb->dst = &rtres->u.dst;
1883 return err; 1880 return err;
1884#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */ 1881#else /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
1885 return ip_mkroute_input_def(skb, res, fl, in_dev, daddr, saddr, tos); 1882 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,
2208 goto cleanup; 2205 goto cleanup;
2209 } 2206 }
2210 2207
2208 atomic_set(&rth->u.dst.__refcnt, 1);
2211 rth->u.dst.flags= DST_HOST; 2209 rth->u.dst.flags= DST_HOST;
2212#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED 2210#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
2213 if (res->fi) { 2211 if (res->fi) {
@@ -2290,8 +2288,6 @@ static inline int ip_mkroute_output_def(struct rtable **rp,
2290 if (err == 0) { 2288 if (err == 0) {
2291 u32 tos = RT_FL_TOS(oldflp); 2289 u32 tos = RT_FL_TOS(oldflp);
2292 2290
2293 atomic_set(&rth->u.dst.__refcnt, 1);
2294
2295 hash = rt_hash_code(oldflp->fl4_dst, 2291 hash = rt_hash_code(oldflp->fl4_dst,
2296 oldflp->fl4_src ^ (oldflp->oif << 5), tos); 2292 oldflp->fl4_src ^ (oldflp->oif << 5), tos);
2297 err = rt_intern_hash(hash, rth, rp); 2293 err = rt_intern_hash(hash, rth, rp);
@@ -2326,6 +2322,10 @@ static inline int ip_mkroute_output(struct rtable** rp,
2326 dev2nexthop = FIB_RES_DEV(*res); 2322 dev2nexthop = FIB_RES_DEV(*res);
2327 dev_hold(dev2nexthop); 2323 dev_hold(dev2nexthop);
2328 2324
2325 /* put reference to previous result */
2326 if (hop)
2327 ip_rt_put(*rp);
2328
2329 err = __mkroute_output(&rth, res, fl, oldflp, 2329 err = __mkroute_output(&rth, res, fl, oldflp,
2330 dev2nexthop, flags); 2330 dev2nexthop, flags);
2331 2331
@@ -2350,7 +2350,6 @@ static inline int ip_mkroute_output(struct rtable** rp,
2350 if (err != 0) 2350 if (err != 0)
2351 return err; 2351 return err;
2352 } 2352 }
2353 atomic_set(&(*rp)->u.dst.__refcnt, 1);
2354 return err; 2353 return err;
2355 } else { 2354 } else {
2356 return ip_mkroute_output_def(rp, res, fl, oldflp, dev_out, 2355 return ip_mkroute_output_def(rp, res, fl, oldflp, dev_out,