OSDN Git Service

nf: xt_qtaguid: fix handling for cases where tunnels are used.
authorJP Abgrall <jpa@google.com>
Sat, 21 Dec 2013 00:51:11 +0000 (16:51 -0800)
committerGerrit - the friendly Code Review server <code-review@localhost>
Mon, 29 Aug 2016 20:59:18 +0000 (13:59 -0700)
* 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>
net/netfilter/xt_qtaguid.c

index e2e7d54..6860d67 100644 (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);
-               }
-       }
-
-       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);
+       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_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);
 
        /*