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

Commit 89d32dc3 authored by JP Abgrall's avatar JP Abgrall Committed by Chenbo Feng
Browse files

ANDROID: nf: xt_qtaguid: fix handling for cases where tunnels are used.



* fix skb->dev vs par->in/out
When there is some forwarding going on, it introduces extra state
around devs associated with xt_action_param->in/out and sk_buff->dev.
E.g.
   par->in and par->out are both set, or
   skb->dev and par->out are both set (and different)
This would lead qtaguid to make the wrong assumption about the
direction and update the wrong device stats.
Now we rely more on par->in/out.

* Fix handling when qtaguid is used as "owner"
When qtaguid is used as an owner module, and sk_socket->file is
not there (happens when tunnels are involved), it would
incorrectly do a tag stats update.

* Correct debug messages.

Bug: 11687690
Change-Id: I2b1ff8bd7131969ce9e25f8291d83a6280b3ba7f
CRs-Fixed: 747810
Signed-off-by: default avatarJP Abgrall <jpa@google.com>
Git-commit: 2b71479d6f5fe8f33b335f713380f72037244395
Git-repo: https://www.codeaurora.org/cgit/quic/la/kernel/mediatek


[imaund@codeaurora.org: Resolved trivial context conflicts.]
Signed-off-by: default avatarIan Maund <imaund@codeaurora.org>
[bflowers@codeaurora.org: Resolved merge conflicts]
Signed-off-by: default avatarBryse Flowers <bflowers@codeaurora.org>
Signed-off-by: default avatarChenbo Feng <fengc@google.com>
parent a52afc8c
Loading
Loading
Loading
Loading
+69 −75
Original line number Original line Diff line number Diff line
@@ -1174,6 +1174,38 @@ static void iface_stat_update(struct net_device *net_dev, bool stash_only)
	spin_unlock_bh(&iface_stat_list_lock);
	spin_unlock_bh(&iface_stat_list_lock);
}
}


/* Guarantied to return a net_device that has a name */
static void get_dev_and_dir(const struct sk_buff *skb,
			    struct xt_action_param *par,
			    enum ifs_tx_rx *direction,
			    const struct net_device **el_dev)
{
	BUG_ON(!direction || !el_dev);

	if (par->in) {
		*el_dev = par->in;
		*direction = IFS_RX;
	} else if (par->out) {
		*el_dev = par->out;
		*direction = IFS_TX;
	} else {
		pr_err("qtaguid[%d]: %s(): no par->in/out?!!\n",
		       par->hooknum, __func__);
		BUG();
	}
	if (unlikely(!(*el_dev)->name)) {
		pr_err("qtaguid[%d]: %s(): no dev->name?!!\n",
		       par->hooknum, __func__);
		BUG();
	}
	if (skb->dev && *el_dev != skb->dev) {
		MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs par->%s=%p %s\n",
			 par->hooknum, skb->dev, skb->dev->name,
			 *direction == IFS_RX ? "in" : "out",  *el_dev,
			 (*el_dev)->name);
	}
}

/*
/*
 * Update stats for the specified interface from the skb.
 * Update stats for the specified interface from the skb.
 * Do nothing if the entry
 * Do nothing if the entry
@@ -1185,46 +1217,27 @@ static void iface_stat_update_from_skb(const struct sk_buff *skb,
{
{
	struct iface_stat *entry;
	struct iface_stat *entry;
	const struct net_device *el_dev;
	const struct net_device *el_dev;
	enum ifs_tx_rx direction = par->in ? IFS_RX : IFS_TX;
	enum ifs_tx_rx direction;
	int bytes = skb->len;
	int bytes = skb->len;
	int proto;
	int proto;


	if (!skb->dev) {
	get_dev_and_dir(skb, par, &direction, &el_dev);
		MT_DEBUG("qtaguid[%d]: no skb->dev\n", par->hooknum);
		el_dev = par->in ? : par->out;
	} else {
		const struct net_device *other_dev;
		el_dev = skb->dev;
		other_dev = par->in ? : par->out;
		if (el_dev != other_dev) {
			MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs "
				 "par->(in/out)=%p %s\n",
				 par->hooknum, el_dev, el_dev->name, other_dev,
				 other_dev->name);
		}
	}

	if (unlikely(!el_dev)) {
		pr_err_ratelimited("qtaguid[%d]: %s(): no par->in/out?!!\n",
				   par->hooknum, __func__);
		BUG();
	} else {
	proto = ipx_proto(skb, par);
	proto = ipx_proto(skb, par);
		MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d\n",
	MT_DEBUG("qtaguid[%d]: iface_stat: %s(%s): "
			 par->hooknum, el_dev->name, el_dev->type,
		 "type=%d fam=%d proto=%d dir=%d\n",
			 par->family, proto);
		 par->hooknum, __func__, el_dev->name, el_dev->type,
	}
		 par->family, proto, direction);


	spin_lock_bh(&iface_stat_list_lock);
	spin_lock_bh(&iface_stat_list_lock);
	entry = get_iface_entry(el_dev->name);
	entry = get_iface_entry(el_dev->name);
	if (entry == NULL) {
	if (entry == NULL) {
		IF_DEBUG("qtaguid: iface_stat: %s(%s): not tracked\n",
		IF_DEBUG("qtaguid[%d]: iface_stat: %s(%s): not tracked\n",
			 __func__, el_dev->name);
			 par->hooknum, __func__, el_dev->name);
		spin_unlock_bh(&iface_stat_list_lock);
		spin_unlock_bh(&iface_stat_list_lock);
		return;
		return;
	}
	}


	IF_DEBUG("qtaguid: %s(%s): entry=%p\n", __func__,
	IF_DEBUG("qtaguid[%d]: %s(%s): entry=%p\n", par->hooknum,  __func__,
		 el_dev->name, entry);
		 el_dev->name, entry);


	data_counters_update(&entry->totals_via_skb, 0, direction, proto,
	data_counters_update(&entry->totals_via_skb, 0, direction, proto,
@@ -1289,14 +1302,14 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
	spin_lock_bh(&iface_stat_list_lock);
	spin_lock_bh(&iface_stat_list_lock);
	iface_entry = get_iface_entry(ifname);
	iface_entry = get_iface_entry(ifname);
	if (!iface_entry) {
	if (!iface_entry) {
		pr_err_ratelimited("qtaguid: iface_stat: stat_update() "
		pr_err_ratelimited("qtaguid: tag_stat: stat_update() "
				   "%s not found\n", ifname);
				   "%s not found\n", ifname);
		spin_unlock_bh(&iface_stat_list_lock);
		spin_unlock_bh(&iface_stat_list_lock);
		return;
		return;
	}
	}
	/* It is ok to process data when an iface_entry is inactive */
	/* It is ok to process data when an iface_entry is inactive */


	MT_DEBUG("qtaguid: iface_stat: stat_update() dev=%s entry=%p\n",
	MT_DEBUG("qtaguid: tag_stat: stat_update() dev=%s entry=%p\n",
		 ifname, iface_entry);
		 ifname, iface_entry);


	/*
	/*
@@ -1313,7 +1326,7 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
		tag = combine_atag_with_uid(acct_tag, uid);
		tag = combine_atag_with_uid(acct_tag, uid);
		uid_tag = make_tag_from_uid(uid);
		uid_tag = make_tag_from_uid(uid);
	}
	}
	MT_DEBUG("qtaguid: iface_stat: stat_update(): "
	MT_DEBUG("qtaguid: tag_stat: stat_update(): "
		 " looking for tag=0x%llx (uid=%u) in ife=%p\n",
		 " looking for tag=0x%llx (uid=%u) in ife=%p\n",
		 tag, get_uid_from_tag(tag), iface_entry);
		 tag, get_uid_from_tag(tag), iface_entry);
	/* Loop over tag list under this interface for {acct_tag,uid_tag} */
	/* Loop over tag list under this interface for {acct_tag,uid_tag} */
@@ -1573,8 +1586,8 @@ static struct sock *qtaguid_find_sk(const struct sk_buff *skb,
	struct sock *sk;
	struct sock *sk;
	unsigned int hook_mask = (1 << par->hooknum);
	unsigned int hook_mask = (1 << par->hooknum);


	MT_DEBUG("qtaguid: find_sk(skb=%p) hooknum=%d family=%d\n", skb,
	MT_DEBUG("qtaguid[%d]: find_sk(skb=%p) family=%d\n",
		 par->hooknum, par->family);
		 par->hooknum, skb, par->family);


	/*
	/*
	 * Let's not abuse the the xt_socket_get*_sk(), or else it will
	 * Let's not abuse the the xt_socket_get*_sk(), or else it will
@@ -1595,8 +1608,8 @@ static struct sock *qtaguid_find_sk(const struct sk_buff *skb,
	}
	}


	if (sk) {
	if (sk) {
		MT_DEBUG("qtaguid: %p->sk_proto=%u "
		MT_DEBUG("qtaguid[%d]: %p->sk_proto=%u->sk_state=%d\n",
			 "->sk_state=%d\n", sk, sk->sk_protocol, sk->sk_state);
			 par->hooknum, sk, sk->sk_protocol, sk->sk_state);
	}
	}
	return sk;
	return sk;
}
}
@@ -1606,36 +1619,20 @@ static void account_for_uid(const struct sk_buff *skb,
			    struct xt_action_param *par)
			    struct xt_action_param *par)
{
{
	const struct net_device *el_dev;
	const struct net_device *el_dev;
	enum ifs_tx_rx direction;
	int proto;


	if (!skb->dev) {
	get_dev_and_dir(skb, par, &direction, &el_dev);
		MT_DEBUG("qtaguid[%d]: no skb->dev\n", par->hooknum);
	proto = ipx_proto(skb, par);
		el_dev = par->in ? : par->out;
	MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d dir=%d\n",
	} else {
		const struct net_device *other_dev;
		el_dev = skb->dev;
		other_dev = par->in ? : par->out;
		if (el_dev != other_dev) {
			MT_DEBUG("qtaguid[%d]: skb->dev=%p %s vs "
				"par->(in/out)=%p %s\n",
				par->hooknum, el_dev, el_dev->name, other_dev,
				other_dev->name);
		}
	}

	if (unlikely(!el_dev)) {
		pr_info("qtaguid[%d]: no par->in/out?!!\n", par->hooknum);
	} else {
		int proto = ipx_proto(skb, par);
		MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d\n",
		 par->hooknum, el_dev->name, el_dev->type,
		 par->hooknum, el_dev->name, el_dev->type,
			 par->family, proto);
		 par->family, proto, direction);


	if_tag_stat_update(el_dev->name, uid,
	if_tag_stat_update(el_dev->name, uid,
			   skb->sk ? skb->sk : alternate_sk,
			   skb->sk ? skb->sk : alternate_sk,
				par->in ? IFS_RX : IFS_TX,
			   direction,
			   proto, skb->len);
			   proto, skb->len);
}
}
}


static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
{
{
@@ -1646,6 +1643,11 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
	kuid_t sock_uid;
	kuid_t sock_uid;
	bool res;
	bool res;
	bool set_sk_callback_lock = false;
	bool set_sk_callback_lock = false;
	/*
	 * TODO: unhack how to force just accounting.
	 * For now we only do tag stats when the uid-owner is not requested
	 */
	bool do_tag_stat = !(info->match & XT_QTAGUID_UID);


	if (unlikely(module_passive))
	if (unlikely(module_passive))
		return (info->match ^ info->invert) == 0;
		return (info->match ^ info->invert) == 0;
@@ -1734,12 +1736,7 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
		 * couldn't find the owner, so for now we just count them
		 * couldn't find the owner, so for now we just count them
		 * against the system.
		 * against the system.
		 */
		 */
		/*
		if (do_tag_stat)
		 * TODO: unhack how to force just accounting.
		 * For now we only do iface stats when the uid-owner is not
		 * requested.
		 */
		if (!(info->match & XT_QTAGUID_UID))
			account_for_uid(skb, sk, 0, par);
			account_for_uid(skb, sk, 0, par);
		MT_DEBUG("qtaguid[%d]: leaving (sk?sk->sk_socket)=%p\n",
		MT_DEBUG("qtaguid[%d]: leaving (sk?sk->sk_socket)=%p\n",
			par->hooknum,
			par->hooknum,
@@ -1754,6 +1751,7 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
	filp = sk->sk_socket->file;
	filp = sk->sk_socket->file;
	if (filp == NULL) {
	if (filp == NULL) {
		MT_DEBUG("qtaguid[%d]: leaving filp=NULL\n", par->hooknum);
		MT_DEBUG("qtaguid[%d]: leaving filp=NULL\n", par->hooknum);
		if (do_tag_stat)
			account_for_uid(skb, sk, 0, par);
			account_for_uid(skb, sk, 0, par);
		res = ((info->match ^ info->invert) &
		res = ((info->match ^ info->invert) &
			(XT_QTAGUID_UID | XT_QTAGUID_GID)) == 0;
			(XT_QTAGUID_UID | XT_QTAGUID_GID)) == 0;
@@ -1761,11 +1759,7 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
		goto put_sock_ret_res;
		goto put_sock_ret_res;
	}
	}
	sock_uid = filp->f_cred->fsuid;
	sock_uid = filp->f_cred->fsuid;
	/*
	if (do_tag_stat)
	 * TODO: unhack how to force just accounting.
	 * For now we only do iface stats when the uid-owner is not requested
	 */
	if (!(info->match & XT_QTAGUID_UID))
		account_for_uid(skb, sk, from_kuid(&init_user_ns, sock_uid), par);
		account_for_uid(skb, sk, from_kuid(&init_user_ns, sock_uid), par);


	/*
	/*