diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2010-03-14 16:13:19 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-03-15 19:00:50 -0400 |
commit | d14a0ebda7d3daede1a99c01527affb9ceaa4c22 (patch) | |
tree | 8bee27033c0e771a9df0c3e8cc3f1dc1091587f0 /net | |
parent | b8d689743106bab5c49dda87080e76aa78db8a56 (diff) |
net-2.6 [Bug-Fix][dccp]: fix oops caused after failed initialisation
dccp: fix panic caused by failed initialisation
This fixes a kernel panic reported thanks to Andre Noll:
if DCCP is compiled into the kernel and any out of the initialisation
steps in net/dccp/proto.c:dccp_init() fail, a subsequent attempt to create
a SOCK_DCCP socket will panic, since inet{,6}_create() are not prevented
from creating DCCP sockets.
This patch fixes the problem by propagating a failure in dccp_init() to
dccp_v{4,6}_init_net(), and from there to dccp_v{4,6}_init(), so that the
DCCP protocol is not made available if its initialisation fails.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/dccp/ipv4.c | 8 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 8 | ||||
-rw-r--r-- | net/dccp/proto.c | 16 |
3 files changed, 17 insertions, 15 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index b195c4feaa0..4071eaf2b36 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c | |||
@@ -998,11 +998,11 @@ static struct inet_protosw dccp_v4_protosw = { | |||
998 | 998 | ||
999 | static int __net_init dccp_v4_init_net(struct net *net) | 999 | static int __net_init dccp_v4_init_net(struct net *net) |
1000 | { | 1000 | { |
1001 | int err; | 1001 | if (dccp_hashinfo.bhash == NULL) |
1002 | return -ESOCKTNOSUPPORT; | ||
1002 | 1003 | ||
1003 | err = inet_ctl_sock_create(&net->dccp.v4_ctl_sk, PF_INET, | 1004 | return inet_ctl_sock_create(&net->dccp.v4_ctl_sk, PF_INET, |
1004 | SOCK_DCCP, IPPROTO_DCCP, net); | 1005 | SOCK_DCCP, IPPROTO_DCCP, net); |
1005 | return err; | ||
1006 | } | 1006 | } |
1007 | 1007 | ||
1008 | static void __net_exit dccp_v4_exit_net(struct net *net) | 1008 | static void __net_exit dccp_v4_exit_net(struct net *net) |
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 1aec6349e85..af3394df63b 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -1191,11 +1191,11 @@ static struct inet_protosw dccp_v6_protosw = { | |||
1191 | 1191 | ||
1192 | static int __net_init dccp_v6_init_net(struct net *net) | 1192 | static int __net_init dccp_v6_init_net(struct net *net) |
1193 | { | 1193 | { |
1194 | int err; | 1194 | if (dccp_hashinfo.bhash == NULL) |
1195 | return -ESOCKTNOSUPPORT; | ||
1195 | 1196 | ||
1196 | err = inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6, | 1197 | return inet_ctl_sock_create(&net->dccp.v6_ctl_sk, PF_INET6, |
1197 | SOCK_DCCP, IPPROTO_DCCP, net); | 1198 | SOCK_DCCP, IPPROTO_DCCP, net); |
1198 | return err; | ||
1199 | } | 1199 | } |
1200 | 1200 | ||
1201 | static void __net_exit dccp_v6_exit_net(struct net *net) | 1201 | static void __net_exit dccp_v6_exit_net(struct net *net) |
diff --git a/net/dccp/proto.c b/net/dccp/proto.c index 0ef7061920c..aa4cef374fd 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c | |||
@@ -1036,7 +1036,7 @@ static int __init dccp_init(void) | |||
1036 | FIELD_SIZEOF(struct sk_buff, cb)); | 1036 | FIELD_SIZEOF(struct sk_buff, cb)); |
1037 | rc = percpu_counter_init(&dccp_orphan_count, 0); | 1037 | rc = percpu_counter_init(&dccp_orphan_count, 0); |
1038 | if (rc) | 1038 | if (rc) |
1039 | goto out; | 1039 | goto out_fail; |
1040 | rc = -ENOBUFS; | 1040 | rc = -ENOBUFS; |
1041 | inet_hashinfo_init(&dccp_hashinfo); | 1041 | inet_hashinfo_init(&dccp_hashinfo); |
1042 | dccp_hashinfo.bind_bucket_cachep = | 1042 | dccp_hashinfo.bind_bucket_cachep = |
@@ -1125,8 +1125,9 @@ static int __init dccp_init(void) | |||
1125 | goto out_sysctl_exit; | 1125 | goto out_sysctl_exit; |
1126 | 1126 | ||
1127 | dccp_timestamping_init(); | 1127 | dccp_timestamping_init(); |
1128 | out: | 1128 | |
1129 | return rc; | 1129 | return 0; |
1130 | |||
1130 | out_sysctl_exit: | 1131 | out_sysctl_exit: |
1131 | dccp_sysctl_exit(); | 1132 | dccp_sysctl_exit(); |
1132 | out_ackvec_exit: | 1133 | out_ackvec_exit: |
@@ -1135,18 +1136,19 @@ out_free_dccp_mib: | |||
1135 | dccp_mib_exit(); | 1136 | dccp_mib_exit(); |
1136 | out_free_dccp_bhash: | 1137 | out_free_dccp_bhash: |
1137 | free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order); | 1138 | free_pages((unsigned long)dccp_hashinfo.bhash, bhash_order); |
1138 | dccp_hashinfo.bhash = NULL; | ||
1139 | out_free_dccp_locks: | 1139 | out_free_dccp_locks: |
1140 | inet_ehash_locks_free(&dccp_hashinfo); | 1140 | inet_ehash_locks_free(&dccp_hashinfo); |
1141 | out_free_dccp_ehash: | 1141 | out_free_dccp_ehash: |
1142 | free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order); | 1142 | free_pages((unsigned long)dccp_hashinfo.ehash, ehash_order); |
1143 | dccp_hashinfo.ehash = NULL; | ||
1144 | out_free_bind_bucket_cachep: | 1143 | out_free_bind_bucket_cachep: |
1145 | kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); | 1144 | kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); |
1146 | dccp_hashinfo.bind_bucket_cachep = NULL; | ||
1147 | out_free_percpu: | 1145 | out_free_percpu: |
1148 | percpu_counter_destroy(&dccp_orphan_count); | 1146 | percpu_counter_destroy(&dccp_orphan_count); |
1149 | goto out; | 1147 | out_fail: |
1148 | dccp_hashinfo.bhash = NULL; | ||
1149 | dccp_hashinfo.ehash = NULL; | ||
1150 | dccp_hashinfo.bind_bucket_cachep = NULL; | ||
1151 | return rc; | ||
1150 | } | 1152 | } |
1151 | 1153 | ||
1152 | static void __exit dccp_fini(void) | 1154 | static void __exit dccp_fini(void) |