| From bf86395b6aae4caf878235811a22ed7fce153b93 Mon Sep 17 00:00:00 2001 |
| From: Taehee Yoo <ap420073@gmail.com> |
| Date: Wed, 11 Dec 2019 08:23:17 +0000 |
| Subject: [PATCH] gtp: fix wrong condition in gtp_genl_dump_pdp() |
| |
| commit 94a6d9fb88df43f92d943c32b84ce398d50bf49f upstream. |
| |
| gtp_genl_dump_pdp() is ->dumpit() callback of GTP module and it is used |
| to dump pdp contexts. it would be re-executed because of dump packet size. |
| |
| If dump packet size is too big, it saves current dump pointer |
| (gtp interface pointer, bucket, TID value) then it restarts dump from |
| last pointer. |
| Current GTP code allows adding zero TID pdp context but dump code |
| ignores zero TID value. So, last dump pointer will not be found. |
| |
| In addition, this patch adds missing rcu_read_lock() in |
| gtp_genl_dump_pdp(). |
| |
| Fixes: 459aa660eb1d ("gtp: add initial driver for datapath of GPRS Tunneling Protocol (GTP-U)") |
| Signed-off-by: Taehee Yoo <ap420073@gmail.com> |
| Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c |
| index 71b34ff8e7eb..7bbc1be3490d 100644 |
| --- a/drivers/net/gtp.c |
| +++ b/drivers/net/gtp.c |
| @@ -38,7 +38,6 @@ struct pdp_ctx { |
| struct hlist_node hlist_addr; |
| |
| union { |
| - u64 tid; |
| struct { |
| u64 tid; |
| u16 flow; |
| @@ -1232,43 +1231,46 @@ static int gtp_genl_dump_pdp(struct sk_buff *skb, |
| struct netlink_callback *cb) |
| { |
| struct gtp_dev *last_gtp = (struct gtp_dev *)cb->args[2], *gtp; |
| + int i, j, bucket = cb->args[0], skip = cb->args[1]; |
| struct net *net = sock_net(skb->sk); |
| - struct gtp_net *gn = net_generic(net, gtp_net_id); |
| - unsigned long tid = cb->args[1]; |
| - int i, k = cb->args[0], ret; |
| struct pdp_ctx *pctx; |
| + struct gtp_net *gn; |
| + |
| + gn = net_generic(net, gtp_net_id); |
| |
| if (cb->args[4]) |
| return 0; |
| |
| + rcu_read_lock(); |
| list_for_each_entry_rcu(gtp, &gn->gtp_dev_list, list) { |
| if (last_gtp && last_gtp != gtp) |
| continue; |
| else |
| last_gtp = NULL; |
| |
| - for (i = k; i < gtp->hash_size; i++) { |
| - hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], hlist_tid) { |
| - if (tid && tid != pctx->u.tid) |
| - continue; |
| - else |
| - tid = 0; |
| - |
| - ret = gtp_genl_fill_info(skb, |
| - NETLINK_CB(cb->skb).portid, |
| - cb->nlh->nlmsg_seq, |
| - cb->nlh->nlmsg_type, pctx); |
| - if (ret < 0) { |
| + for (i = bucket; i < gtp->hash_size; i++) { |
| + j = 0; |
| + hlist_for_each_entry_rcu(pctx, >p->tid_hash[i], |
| + hlist_tid) { |
| + if (j >= skip && |
| + gtp_genl_fill_info(skb, |
| + NETLINK_CB(cb->skb).portid, |
| + cb->nlh->nlmsg_seq, |
| + cb->nlh->nlmsg_type, pctx)) { |
| cb->args[0] = i; |
| - cb->args[1] = pctx->u.tid; |
| + cb->args[1] = j; |
| cb->args[2] = (unsigned long)gtp; |
| goto out; |
| } |
| + j++; |
| } |
| + skip = 0; |
| } |
| + bucket = 0; |
| } |
| cb->args[4] = 1; |
| out: |
| + rcu_read_unlock(); |
| return skb->len; |
| } |
| |
| -- |
| 2.7.4 |
| |