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: JP 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: Ian Maund <imaund@codeaurora.org>
[bflowers@codeaurora.org: Resolved merge conflicts]
Signed-off-by: Bryse Flowers <bflowers@codeaurora.org>
This commit is contained in:
JP Abgrall 2013-12-20 16:51:11 -08:00 committed by Gerrit - the friendly Code Review server
parent aaf356abef
commit 97a4ac881a

View file

@ -1175,6 +1175,38 @@ static void iface_stat_update(struct net_device *net_dev, bool stash_only)
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.
* Do nothing if the entry
@ -1186,50 +1218,27 @@ static void iface_stat_update_from_skb(const struct sk_buff *skb,
{
struct iface_stat *entry;
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 proto;
if (!skb->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 if (unlikely(!el_dev->name)) {
pr_err_ratelimited("qtaguid[%d]: %s(): no dev->name?!!\n",
par->hooknum, __func__);
BUG();
} else {
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->family, proto);
}
get_dev_and_dir(skb, par, &direction, &el_dev);
proto = ipx_proto(skb, par);
MT_DEBUG("qtaguid[%d]: iface_stat: %s(%s): "
"type=%d fam=%d proto=%d dir=%d\n",
par->hooknum, __func__, el_dev->name, el_dev->type,
par->family, proto, direction);
spin_lock_bh(&iface_stat_list_lock);
entry = get_iface_entry(el_dev->name);
if (entry == NULL) {
IF_DEBUG("qtaguid: iface_stat: %s(%s): not tracked\n",
__func__, el_dev->name);
IF_DEBUG("qtaguid[%d]: iface_stat: %s(%s): not tracked\n",
par->hooknum, __func__, el_dev->name);
spin_unlock_bh(&iface_stat_list_lock);
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);
data_counters_update(&entry->totals_via_skb, 0, direction, proto,
@ -1294,14 +1303,14 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
spin_lock_bh(&iface_stat_list_lock);
iface_entry = get_iface_entry(ifname);
if (!iface_entry) {
pr_err_ratelimited("qtaguid: iface_stat: stat_update() "
pr_err_ratelimited("qtaguid: tag_stat: stat_update() "
"%s not found\n", ifname);
spin_unlock_bh(&iface_stat_list_lock);
return;
}
/* 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);
/*
@ -1318,7 +1327,7 @@ static void if_tag_stat_update(const char *ifname, uid_t uid,
tag = combine_atag_with_uid(acct_tag, 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",
tag, get_uid_from_tag(tag), iface_entry);
/* Loop over tag list under this interface for {acct_tag,uid_tag} */
@ -1578,8 +1587,8 @@ static struct sock *qtaguid_find_sk(const struct sk_buff *skb,
struct sock *sk;
unsigned int hook_mask = (1 << par->hooknum);
MT_DEBUG("qtaguid: find_sk(skb=%p) hooknum=%d family=%d\n", skb,
par->hooknum, par->family);
MT_DEBUG("qtaguid[%d]: find_sk(skb=%p) family=%d\n",
par->hooknum, skb, par->family);
/*
* Let's not abuse the the xt_socket_get*_sk(), or else it will
@ -1600,8 +1609,8 @@ static struct sock *qtaguid_find_sk(const struct sk_buff *skb,
}
if (sk) {
MT_DEBUG("qtaguid: %p->sk_proto=%u "
"->sk_state=%d\n", sk, sk->sk_protocol, sk->sk_state);
MT_DEBUG("qtaguid[%d]: %p->sk_proto=%u->sk_state=%d\n",
par->hooknum, sk, sk->sk_protocol, sk->sk_state);
/*
* When in TCP_TIME_WAIT the sk is not a "struct sock" but
* "struct inet_timewait_sock" which is missing fields.
@ -1619,37 +1628,19 @@ static void account_for_uid(const struct sk_buff *skb,
struct xt_action_param *par)
{
const struct net_device *el_dev;
enum ifs_tx_rx direction;
int proto;
if (!skb->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);
}
}
get_dev_and_dir(skb, par, &direction, &el_dev);
proto = ipx_proto(skb, par);
MT_DEBUG("qtaguid[%d]: dev name=%s type=%d fam=%d proto=%d dir=%d\n",
par->hooknum, el_dev->name, el_dev->type,
par->family, proto, direction);
if (unlikely(!el_dev)) {
pr_info("qtaguid[%d]: no par->in/out?!!\n", par->hooknum);
} else if (unlikely(!el_dev->name)) {
pr_info("qtaguid[%d]: no dev->name?!!\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->family, proto);
if_tag_stat_update(el_dev->name, uid,
skb->sk ? skb->sk : alternate_sk,
par->in ? IFS_RX : IFS_TX,
proto, skb->len);
}
if_tag_stat_update(el_dev->name, uid,
skb->sk ? skb->sk : alternate_sk,
direction,
proto, skb->len);
}
static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
@ -1661,6 +1652,11 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
kuid_t sock_uid;
bool res;
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))
return (info->match ^ info->invert) == 0;
@ -1734,12 +1730,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
* against the system.
*/
/*
* 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))
if (do_tag_stat)
account_for_uid(skb, sk, 0, par);
MT_DEBUG("qtaguid[%d]: leaving (sk?sk->sk_socket)=%p\n",
par->hooknum,
@ -1754,18 +1745,15 @@ static bool qtaguid_mt(const struct sk_buff *skb, struct xt_action_param *par)
filp = sk->sk_socket->file;
if (filp == NULL) {
MT_DEBUG("qtaguid[%d]: leaving filp=NULL\n", par->hooknum);
account_for_uid(skb, sk, 0, par);
if (do_tag_stat)
account_for_uid(skb, sk, 0, par);
res = ((info->match ^ info->invert) &
(XT_QTAGUID_UID | XT_QTAGUID_GID)) == 0;
atomic64_inc(&qtu_events.match_no_sk_file);
goto put_sock_ret_res;
}
sock_uid = filp->f_cred->fsuid;
/*
* 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))
if (do_tag_stat)
account_for_uid(skb, sk, from_kuid(&init_user_ns, sock_uid), par);
/*