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

This commit is contained in:
Linux Build Service Account 2016-09-02 13:52:34 -07:00 committed by Gerrit - the friendly Code Review server
commit 86ed229775

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); 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
@ -1186,50 +1218,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); proto = ipx_proto(skb, par);
el_dev = par->in ? : par->out; MT_DEBUG("qtaguid[%d]: iface_stat: %s(%s): "
} else { "type=%d fam=%d proto=%d dir=%d\n",
const struct net_device *other_dev; par->hooknum, __func__, el_dev->name, el_dev->type,
el_dev = skb->dev; par->family, proto, direction);
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);
}
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,
@ -1294,14 +1303,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);
/* /*
@ -1318,7 +1327,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} */
@ -1578,8 +1587,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
@ -1600,8 +1609,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);
/* /*
* When in TCP_TIME_WAIT the sk is not a "struct sock" but * When in TCP_TIME_WAIT the sk is not a "struct sock" but
* "struct inet_timewait_sock" which is missing fields. * "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) 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 { par->hooknum, el_dev->name, el_dev->type,
const struct net_device *other_dev; par->family, proto, direction);
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)) { if_tag_stat_update(el_dev->name, uid,
pr_info("qtaguid[%d]: no par->in/out?!!\n", par->hooknum); skb->sk ? skb->sk : alternate_sk,
} else if (unlikely(!el_dev->name)) { direction,
pr_info("qtaguid[%d]: no dev->name?!!\n", par->hooknum); proto, skb->len);
} 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);
}
} }
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)
@ -1661,6 +1652,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 +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 * 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,18 +1745,15 @@ 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);
account_for_uid(skb, sk, 0, par); if (do_tag_stat)
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;
atomic64_inc(&qtu_events.match_no_sk_file); atomic64_inc(&qtu_events.match_no_sk_file);
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);
/* /*