netfilter: xt_owner: Add supplementary groups option
authorLukasz Pawelczyk <l.pawelczyk@samsung.com>
Fri, 10 May 2019 11:46:22 +0000 (13:46 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Fri, 31 May 2019 16:02:41 +0000 (18:02 +0200)
The XT_OWNER_SUPPL_GROUPS flag causes GIDs specified with XT_OWNER_GID
to be also checked in the supplementary groups of a process.

f_cred->group_info cannot be modified during its lifetime and f_cred
holds a reference to it so it's safe to use.

Signed-off-by: Lukasz Pawelczyk <l.pawelczyk@samsung.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
include/uapi/linux/netfilter/xt_owner.h
net/netfilter/xt_owner.c

index fa3ad84957d50d9e236f84aabb05679676b285ef..9e98c09eda32741d21bbe85833583fdcc1f67cae 100644 (file)
@@ -5,9 +5,10 @@
 #include <linux/types.h>
 
 enum {
-       XT_OWNER_UID    = 1 << 0,
-       XT_OWNER_GID    = 1 << 1,
-       XT_OWNER_SOCKET = 1 << 2,
+       XT_OWNER_UID          = 1 << 0,
+       XT_OWNER_GID          = 1 << 1,
+       XT_OWNER_SOCKET       = 1 << 2,
+       XT_OWNER_SUPPL_GROUPS = 1 << 3,
 };
 
 struct xt_owner_match_info {
index 46686fb73784bf71c79282e87e3f01f2c0411f5c..a8784502aca6963b808c52e1e6a0a23ae9253cc5 100644 (file)
@@ -91,11 +91,28 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
        }
 
        if (info->match & XT_OWNER_GID) {
+               unsigned int i, match = false;
                kgid_t gid_min = make_kgid(net->user_ns, info->gid_min);
                kgid_t gid_max = make_kgid(net->user_ns, info->gid_max);
-               if ((gid_gte(filp->f_cred->fsgid, gid_min) &&
-                    gid_lte(filp->f_cred->fsgid, gid_max)) ^
-                   !(info->invert & XT_OWNER_GID))
+               struct group_info *gi = filp->f_cred->group_info;
+
+               if (gid_gte(filp->f_cred->fsgid, gid_min) &&
+                   gid_lte(filp->f_cred->fsgid, gid_max))
+                       match = true;
+
+               if (!match && (info->match & XT_OWNER_SUPPL_GROUPS) && gi) {
+                       for (i = 0; i < gi->ngroups; ++i) {
+                               kgid_t group = gi->gid[i];
+
+                               if (gid_gte(group, gid_min) &&
+                                   gid_lte(group, gid_max)) {
+                                       match = true;
+                                       break;
+                               }
+                       }
+               }
+
+               if (match ^ !(info->invert & XT_OWNER_GID))
                        return false;
        }