| From 5135c9738f9bc5ce5ca34d0e0b6cb11a63e636dd Mon Sep 17 00:00:00 2001 |
| From: Daniel Borkmann <dborkman@redhat.com> |
| Date: Sat, 7 Sep 2013 15:13:20 +0200 |
| Subject: net: fib: fib6_add: fix potential NULL pointer dereference |
| |
| From: Daniel Borkmann <dborkman@redhat.com> |
| |
| [ Upstream commit ae7b4e1f213aa659aedf9c6ecad0bf5f0476e1e2 ] |
| |
| When the kernel is compiled with CONFIG_IPV6_SUBTREES, and we return |
| with an error in fn = fib6_add_1(), then error codes are encoded into |
| the return pointer e.g. ERR_PTR(-ENOENT). In such an error case, we |
| write the error code into err and jump to out, hence enter the if(err) |
| condition. Now, if CONFIG_IPV6_SUBTREES is enabled, we check for: |
| |
| if (pn != fn && pn->leaf == rt) |
| ... |
| if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) |
| ... |
| |
| Since pn is NULL and fn is f.e. ERR_PTR(-ENOENT), then pn != fn |
| evaluates to true and causes a NULL-pointer dereference on further |
| checks on pn. Fix it, by setting both NULL in error case, so that |
| pn != fn already evaluates to false and no further dereference |
| takes place. |
| |
| This was first correctly implemented in 4a287eba2 ("IPv6 routing, |
| NLM_F_* flag support: REPLACE and EXCL flags support, warn about |
| missing CREATE flag"), but the bug got later on introduced by |
| 188c517a0 ("ipv6: return errno pointers consistently for fib6_add_1()"). |
| |
| Signed-off-by: Daniel Borkmann <dborkman@redhat.com> |
| Cc: Lin Ming <mlin@ss.pku.edu.cn> |
| Cc: Matti Vaittinen <matti.vaittinen@nsn.com> |
| Cc: Hannes Frederic Sowa <hannes@stressinduktion.org> |
| Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> |
| Acked-by: Matti Vaittinen <matti.vaittinen@nsn.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ipv6/ip6_fib.c | 2 +- |
| 1 file changed, 1 insertion(+), 1 deletion(-) |
| |
| --- a/net/ipv6/ip6_fib.c |
| +++ b/net/ipv6/ip6_fib.c |
| @@ -825,9 +825,9 @@ int fib6_add(struct fib6_node *root, str |
| fn = fib6_add_1(root, &rt->rt6i_dst.addr, sizeof(struct in6_addr), |
| rt->rt6i_dst.plen, offsetof(struct rt6_info, rt6i_dst), |
| allow_create, replace_required); |
| - |
| if (IS_ERR(fn)) { |
| err = PTR_ERR(fn); |
| + fn = NULL; |
| goto out; |
| } |
| |