Message ID | 20241106-tcp-md5-diag-prep-v1-1-d62debf3dded@gmail.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | Make TCP-MD5-diag slightly less broken | expand |
Hi Dmitry,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 2e1b3cc9d7f790145a80cb705b168f05dab65df2]
url: https://github.com/intel-lab-lkp/linux/commits/Dmitry-Safonov-via-B4-Relay/net-diag-Do-not-race-on-dumping-MD5-keys-with-adding-new-MD5-keys/20241107-025054
base: 2e1b3cc9d7f790145a80cb705b168f05dab65df2
patch link: https://lore.kernel.org/r/20241106-tcp-md5-diag-prep-v1-1-d62debf3dded%40gmail.com
patch subject: [PATCH net 1/6] net/diag: Do not race on dumping MD5 keys with adding new MD5 keys
config: arm64-randconfig-003-20241107 (https://download.01.org/0day-ci/archive/20241107/202411071218.G7g6a8JG-lkp@intel.com/config)
compiler: clang version 20.0.0git (https://github.com/llvm/llvm-project 592c0fe55f6d9a811028b5f3507be91458ab2713)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241107/202411071218.G7g6a8JG-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202411071218.G7g6a8JG-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from net/ipv4/tcp_diag.c:9:
In file included from include/linux/net.h:24:
In file included from include/linux/mm.h:2213:
include/linux/vmstat.h:504:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
504 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
505 | item];
| ~~~~
include/linux/vmstat.h:511:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
511 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
512 | NR_VM_NUMA_EVENT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~~
include/linux/vmstat.h:518:36: warning: arithmetic between different enumeration types ('enum node_stat_item' and 'enum lru_list') [-Wenum-enum-conversion]
518 | return node_stat_name(NR_LRU_BASE + lru) + 3; // skip "nr_"
| ~~~~~~~~~~~ ^ ~~~
include/linux/vmstat.h:524:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
524 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
525 | NR_VM_NUMA_EVENT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~~
>> net/ipv4/tcp_diag.c:70:3: warning: variable 'md5sig_count' is uninitialized when used here [-Wuninitialized]
70 | md5sig_count++;
| ^~~~~~~~~~~~
net/ipv4/tcp_diag.c:60:36: note: initialize the variable 'md5sig_count' to silence this warning
60 | unsigned int attrlen, md5sig_count;
| ^
| = 0
5 warnings generated.
vim +/md5sig_count +70 net/ipv4/tcp_diag.c
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 54
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 55 static int tcp_diag_put_md5sig(struct sk_buff *skb,
4a6144fbc706b3c Dmitry Safonov 2024-11-06 56 const struct tcp_md5sig_info *md5sig,
4a6144fbc706b3c Dmitry Safonov 2024-11-06 57 struct nlmsghdr *nlh)
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 58 {
4a6144fbc706b3c Dmitry Safonov 2024-11-06 59 size_t key_size = sizeof(struct tcp_diag_md5sig);
4a6144fbc706b3c Dmitry Safonov 2024-11-06 60 unsigned int attrlen, md5sig_count;
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 61 const struct tcp_md5sig_key *key;
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 62 struct tcp_diag_md5sig *info;
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 63 struct nlattr *attr;
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 64
4a6144fbc706b3c Dmitry Safonov 2024-11-06 65 /*
4a6144fbc706b3c Dmitry Safonov 2024-11-06 66 * Userspace doesn't like to see zero-filled key-values, so
4a6144fbc706b3c Dmitry Safonov 2024-11-06 67 * allocating too large attribute is bad.
4a6144fbc706b3c Dmitry Safonov 2024-11-06 68 */
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 69 hlist_for_each_entry_rcu(key, &md5sig->head, node)
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 @70 md5sig_count++;
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 71 if (md5sig_count == 0)
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 72 return 0;
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 73
4a6144fbc706b3c Dmitry Safonov 2024-11-06 74 attrlen = skb_availroom(skb) - NLA_HDRLEN;
4a6144fbc706b3c Dmitry Safonov 2024-11-06 75 md5sig_count = min(md5sig_count, attrlen / key_size);
4a6144fbc706b3c Dmitry Safonov 2024-11-06 76 attr = nla_reserve(skb, INET_DIAG_MD5SIG, md5sig_count * key_size);
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 77 if (!attr)
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 78 return -EMSGSIZE;
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 79
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 80 info = nla_data(attr);
4a6144fbc706b3c Dmitry Safonov 2024-11-06 81 memset(info, 0, md5sig_count * key_size);
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 82 hlist_for_each_entry_rcu(key, &md5sig->head, node) {
4a6144fbc706b3c Dmitry Safonov 2024-11-06 83 /* More keys on a socket than pre-allocated space available */
4a6144fbc706b3c Dmitry Safonov 2024-11-06 84 if (md5sig_count-- == 0) {
4a6144fbc706b3c Dmitry Safonov 2024-11-06 85 nlh->nlmsg_flags |= NLM_F_DUMP_INTR;
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 86 break;
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 87 }
4a6144fbc706b3c Dmitry Safonov 2024-11-06 88 tcp_diag_md5sig_fill(info++, key);
4a6144fbc706b3c Dmitry Safonov 2024-11-06 89 }
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 90
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 91 return 0;
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 92 }
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 93 #endif
c03fa9bcacd9ac0 Ivan Delalande 2017-08-31 94
diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index a9033696b0aad36ab9abd47e4b68e272053019d7..cb2ba672eba131986d0432dd628fc42bbf800886 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -22,7 +22,8 @@ struct inet_diag_handler { int (*idiag_get_aux)(struct sock *sk, bool net_admin, - struct sk_buff *skb); + struct sk_buff *skb, + struct nlmsghdr *nlh); size_t (*idiag_get_aux_size)(struct sock *sk, bool net_admin); diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 67639309163d05c034fad80fc9a6096c3b79d42f..67b9cc4c0e47a596a4d588e793b7f13ee040a1e3 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -350,10 +350,6 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, handler->idiag_get_info(sk, r, info); - if (ext & (1 << (INET_DIAG_INFO - 1)) && handler->idiag_get_aux) - if (handler->idiag_get_aux(sk, net_admin, skb) < 0) - goto errout; - if (sk->sk_state < TCP_TIME_WAIT) { union tcp_cc_info info; size_t sz = 0; @@ -368,6 +364,10 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, goto errout; } + if (ext & (1 << (INET_DIAG_INFO - 1)) && handler->idiag_get_aux) + if (handler->idiag_get_aux(sk, net_admin, skb, nlh) < 0) + goto errout; + /* Keep it at the end for potential retry with a larger skb, * or else do best-effort fitting, which is only done for the * first_nlmsg. diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index f428ecf9120f2f596e1d67db2b2a0d0d0e211905..36606a19b451f059e32c58c0d76a878dc9be5ff0 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -53,29 +53,39 @@ static void tcp_diag_md5sig_fill(struct tcp_diag_md5sig *info, } static int tcp_diag_put_md5sig(struct sk_buff *skb, - const struct tcp_md5sig_info *md5sig) + const struct tcp_md5sig_info *md5sig, + struct nlmsghdr *nlh) { + size_t key_size = sizeof(struct tcp_diag_md5sig); + unsigned int attrlen, md5sig_count; const struct tcp_md5sig_key *key; struct tcp_diag_md5sig *info; struct nlattr *attr; - int md5sig_count = 0; + /* + * Userspace doesn't like to see zero-filled key-values, so + * allocating too large attribute is bad. + */ hlist_for_each_entry_rcu(key, &md5sig->head, node) md5sig_count++; if (md5sig_count == 0) return 0; - attr = nla_reserve(skb, INET_DIAG_MD5SIG, - md5sig_count * sizeof(struct tcp_diag_md5sig)); + attrlen = skb_availroom(skb) - NLA_HDRLEN; + md5sig_count = min(md5sig_count, attrlen / key_size); + attr = nla_reserve(skb, INET_DIAG_MD5SIG, md5sig_count * key_size); if (!attr) return -EMSGSIZE; info = nla_data(attr); - memset(info, 0, md5sig_count * sizeof(struct tcp_diag_md5sig)); + memset(info, 0, md5sig_count * key_size); hlist_for_each_entry_rcu(key, &md5sig->head, node) { - tcp_diag_md5sig_fill(info++, key); - if (--md5sig_count == 0) + /* More keys on a socket than pre-allocated space available */ + if (md5sig_count-- == 0) { + nlh->nlmsg_flags |= NLM_F_DUMP_INTR; break; + } + tcp_diag_md5sig_fill(info++, key); } return 0; @@ -110,25 +120,11 @@ static int tcp_diag_put_ulp(struct sk_buff *skb, struct sock *sk, } static int tcp_diag_get_aux(struct sock *sk, bool net_admin, - struct sk_buff *skb) + struct sk_buff *skb, struct nlmsghdr *nlh) { struct inet_connection_sock *icsk = inet_csk(sk); int err = 0; -#ifdef CONFIG_TCP_MD5SIG - if (net_admin) { - struct tcp_md5sig_info *md5sig; - - rcu_read_lock(); - md5sig = rcu_dereference(tcp_sk(sk)->md5sig_info); - if (md5sig) - err = tcp_diag_put_md5sig(skb, md5sig); - rcu_read_unlock(); - if (err < 0) - return err; - } -#endif - if (net_admin) { const struct tcp_ulp_ops *ulp_ops; @@ -138,6 +134,21 @@ static int tcp_diag_get_aux(struct sock *sk, bool net_admin, if (err) return err; } + +#ifdef CONFIG_TCP_MD5SIG + if (net_admin) { + struct tcp_md5sig_info *md5sig; + + rcu_read_lock(); + md5sig = rcu_dereference(tcp_sk(sk)->md5sig_info); + if (md5sig) + err = tcp_diag_put_md5sig(skb, md5sig, nlh); + rcu_read_unlock(); + if (err < 0) + return err; + } +#endif + return 0; }