Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 75f08d92 authored by Taehee Yoo's avatar Taehee Yoo Committed by Greg Kroah-Hartman
Browse files

gtp: fix wrong condition in gtp_genl_dump_pdp()



[ Upstream commit 94a6d9fb88df43f92d943c32b84ce398d50bf49f ]

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: 459aa660 ("gtp: add initial driver for datapath of GPRS Tunneling Protocol (GTP-U)")
Signed-off-by: default avatarTaehee Yoo <ap420073@gmail.com>
Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent b2c74eba
Loading
Loading
Loading
Loading
+19 −17
Original line number Diff line number Diff line
@@ -42,7 +42,6 @@ struct pdp_ctx {
	struct hlist_node	hlist_addr;

	union {
		u64		tid;
		struct {
			u64	tid;
			u16	flow;
@@ -1221,43 +1220,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, &gtp->tid_hash[i], hlist_tid) {
				if (tid && tid != pctx->u.tid)
					continue;
				else
					tid = 0;

				ret = gtp_genl_fill_info(skb,
		for (i = bucket; i < gtp->hash_size; i++) {
			j = 0;
			hlist_for_each_entry_rcu(pctx, &gtp->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);
				if (ret < 0) {
					    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;
}