Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

[INET]: Fix inet_diag dead-lock regression

The inet_diag register fix broke inet_diag module loading because the
loaded module had to take the same mutex that's already held by the
loader in order to register the new handler.

This patch fixes it by introducing a separate mutex to protect the
handling of handlers.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>

+46 -21
+46 -21
net/ipv4/inet_diag.c
··· 51 51 #define INET_DIAG_PUT(skb, attrtype, attrlen) \ 52 52 RTA_DATA(__RTA_PUT(skb, attrtype, attrlen)) 53 53 54 + static DEFINE_MUTEX(inet_diag_table_mutex); 55 + 56 + static const struct inet_diag_handler *inet_diag_lock_handler(int type) 57 + { 58 + #ifdef CONFIG_KMOD 59 + if (!inet_diag_table[type]) 60 + request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, 61 + NETLINK_INET_DIAG, type); 62 + #endif 63 + 64 + mutex_lock(&inet_diag_table_mutex); 65 + if (!inet_diag_table[type]) 66 + return ERR_PTR(-ENOENT); 67 + 68 + return inet_diag_table[type]; 69 + } 70 + 71 + static inline void inet_diag_unlock_handler( 72 + const struct inet_diag_handler *handler) 73 + { 74 + mutex_unlock(&inet_diag_table_mutex); 75 + } 76 + 54 77 static int inet_csk_diag_fill(struct sock *sk, 55 78 struct sk_buff *skb, 56 79 int ext, u32 pid, u32 seq, u16 nlmsg_flags, ··· 258 235 struct inet_hashinfo *hashinfo; 259 236 const struct inet_diag_handler *handler; 260 237 261 - handler = inet_diag_table[nlh->nlmsg_type]; 262 - BUG_ON(handler == NULL); 238 + handler = inet_diag_lock_handler(nlh->nlmsg_type); 239 + if (!handler) 240 + return -ENOENT; 241 + 263 242 hashinfo = handler->idiag_hashinfo; 243 + err = -EINVAL; 264 244 265 245 if (req->idiag_family == AF_INET) { 266 246 sk = inet_lookup(hashinfo, req->id.idiag_dst[0], ··· 281 255 } 282 256 #endif 283 257 else { 284 - return -EINVAL; 258 + goto unlock; 285 259 } 286 260 261 + err = -ENOENT; 287 262 if (sk == NULL) 288 - return -ENOENT; 263 + goto unlock; 289 264 290 265 err = -ESTALE; 291 266 if ((req->id.idiag_cookie[0] != INET_DIAG_NOCOOKIE || ··· 323 296 else 324 297 sock_put(sk); 325 298 } 299 + unlock: 300 + inet_diag_unlock_handler(handler); 326 301 return err; 327 302 } 328 303 ··· 707 678 const struct inet_diag_handler *handler; 708 679 struct inet_hashinfo *hashinfo; 709 680 710 - handler = inet_diag_table[cb->nlh->nlmsg_type]; 711 - BUG_ON(handler == NULL); 681 + handler = inet_diag_lock_handler(cb->nlh->nlmsg_type); 682 + if (!handler) 683 + goto no_handler; 684 + 712 685 hashinfo = handler->idiag_hashinfo; 713 686 714 687 s_i = cb->args[1]; ··· 774 743 } 775 744 776 745 if (!(r->idiag_states & ~(TCPF_LISTEN | TCPF_SYN_RECV))) 777 - return skb->len; 746 + goto unlock; 778 747 779 748 for (i = s_i; i < hashinfo->ehash_size; i++) { 780 749 struct inet_ehash_bucket *head = &hashinfo->ehash[i]; ··· 836 805 done: 837 806 cb->args[1] = i; 838 807 cb->args[2] = num; 808 + unlock: 809 + inet_diag_unlock_handler(handler); 810 + no_handler: 839 811 return skb->len; 840 812 } 841 813 ··· 849 815 if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX || 850 816 nlmsg_len(nlh) < hdrlen) 851 817 return -EINVAL; 852 - 853 - #ifdef CONFIG_KMOD 854 - if (inet_diag_table[nlh->nlmsg_type] == NULL) 855 - request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, 856 - NETLINK_INET_DIAG, nlh->nlmsg_type); 857 - #endif 858 - 859 - if (inet_diag_table[nlh->nlmsg_type] == NULL) 860 - return -ENOENT; 861 818 862 819 if (nlh->nlmsg_flags & NLM_F_DUMP) { 863 820 if (nlmsg_attrlen(nlh, hdrlen)) { ··· 886 861 if (type >= INET_DIAG_GETSOCK_MAX) 887 862 goto out; 888 863 889 - mutex_lock(&inet_diag_mutex); 864 + mutex_lock(&inet_diag_table_mutex); 890 865 err = -EEXIST; 891 866 if (inet_diag_table[type] == NULL) { 892 867 inet_diag_table[type] = h; 893 868 err = 0; 894 869 } 895 - mutex_unlock(&inet_diag_mutex); 870 + mutex_unlock(&inet_diag_table_mutex); 896 871 out: 897 872 return err; 898 873 } ··· 905 880 if (type >= INET_DIAG_GETSOCK_MAX) 906 881 return; 907 882 908 - mutex_lock(&inet_diag_mutex); 883 + mutex_lock(&inet_diag_table_mutex); 909 884 inet_diag_table[type] = NULL; 910 - mutex_unlock(&inet_diag_mutex); 885 + mutex_unlock(&inet_diag_table_mutex); 911 886 } 912 887 EXPORT_SYMBOL_GPL(inet_diag_unregister); 913 888 ··· 922 897 goto out; 923 898 924 899 idiagnl = netlink_kernel_create(&init_net, NETLINK_INET_DIAG, 0, 925 - inet_diag_rcv, &inet_diag_mutex, THIS_MODULE); 900 + inet_diag_rcv, NULL, THIS_MODULE); 926 901 if (idiagnl == NULL) 927 902 goto out_free_table; 928 903 err = 0;