Merge "nf: xt_qtaguid: fix handling for cases where tunnels are used."
This commit is contained in:
commit
86ed229775
1 changed files with 69 additions and 81 deletions
|
@ -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);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Add table
Reference in a new issue