Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: implement xt_cgroup cgroup2 path match

This patch implements xt_cgroup path match which matches cgroup2
membership of the associated socket. The match is recursive and
invertible.

For rationales on introducing another cgroup based match, please refer
to a preceding commit "sock, cgroup: add sock->sk_cgroup".

v3: Folded into xt_cgroup as a new revision interface as suggested by
Pablo.

v2: Included linux/limits.h from xt_cgroup2.h for PATH_MAX. Added
explicit alignment to the priv field. Both suggested by Jan.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Daniel Wagner <daniel.wagner@bmw-carit.de>
CC: Neil Horman <nhorman@tuxdriver.com>
Cc: Jan Engelhardt <jengelh@inai.de>
Cc: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Tejun Heo and committed by
Pablo Neira Ayuso
c38c4597 4ec8ff0e

+82
+13
include/uapi/linux/netfilter/xt_cgroup.h
··· 2 2 #define _UAPI_XT_CGROUP_H 3 3 4 4 #include <linux/types.h> 5 + #include <linux/limits.h> 5 6 6 7 struct xt_cgroup_info_v0 { 7 8 __u32 id; 8 9 __u32 invert; 10 + }; 11 + 12 + struct xt_cgroup_info_v1 { 13 + __u8 has_path; 14 + __u8 has_classid; 15 + __u8 invert_path; 16 + __u8 invert_classid; 17 + char path[PATH_MAX]; 18 + __u32 classid; 19 + 20 + /* kernel internal data */ 21 + void *priv __attribute__((aligned(8))); 9 22 }; 10 23 11 24 #endif /* _UAPI_XT_CGROUP_H */
+69
net/netfilter/xt_cgroup.c
··· 34 34 return 0; 35 35 } 36 36 37 + static int cgroup_mt_check_v1(const struct xt_mtchk_param *par) 38 + { 39 + struct xt_cgroup_info_v1 *info = par->matchinfo; 40 + struct cgroup *cgrp; 41 + 42 + if ((info->invert_path & ~1) || (info->invert_classid & ~1)) 43 + return -EINVAL; 44 + 45 + if (!info->has_path && !info->has_classid) { 46 + pr_info("xt_cgroup: no path or classid specified\n"); 47 + return -EINVAL; 48 + } 49 + 50 + if (info->has_path && info->has_classid) { 51 + pr_info("xt_cgroup: both path and classid specified\n"); 52 + return -EINVAL; 53 + } 54 + 55 + if (info->has_path) { 56 + cgrp = cgroup_get_from_path(info->path); 57 + if (IS_ERR(cgrp)) { 58 + pr_info("xt_cgroup: invalid path, errno=%ld\n", 59 + PTR_ERR(cgrp)); 60 + return -EINVAL; 61 + } 62 + info->priv = cgrp; 63 + } 64 + 65 + return 0; 66 + } 67 + 37 68 static bool 38 69 cgroup_mt_v0(const struct sk_buff *skb, struct xt_action_param *par) 39 70 { ··· 77 46 info->invert; 78 47 } 79 48 49 + static bool cgroup_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) 50 + { 51 + const struct xt_cgroup_info_v1 *info = par->matchinfo; 52 + struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data; 53 + struct cgroup *ancestor = info->priv; 54 + 55 + if (!skb->sk || !sk_fullsock(skb->sk)) 56 + return false; 57 + 58 + if (ancestor) 59 + return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^ 60 + info->invert_path; 61 + else 62 + return (info->classid == sock_cgroup_classid(skcd)) ^ 63 + info->invert_classid; 64 + } 65 + 66 + static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par) 67 + { 68 + struct xt_cgroup_info_v1 *info = par->matchinfo; 69 + 70 + if (info->priv) 71 + cgroup_put(info->priv); 72 + } 73 + 80 74 static struct xt_match cgroup_mt_reg[] __read_mostly = { 81 75 { 82 76 .name = "cgroup", ··· 110 54 .checkentry = cgroup_mt_check_v0, 111 55 .match = cgroup_mt_v0, 112 56 .matchsize = sizeof(struct xt_cgroup_info_v0), 57 + .me = THIS_MODULE, 58 + .hooks = (1 << NF_INET_LOCAL_OUT) | 59 + (1 << NF_INET_POST_ROUTING) | 60 + (1 << NF_INET_LOCAL_IN), 61 + }, 62 + { 63 + .name = "cgroup", 64 + .revision = 1, 65 + .family = NFPROTO_UNSPEC, 66 + .checkentry = cgroup_mt_check_v1, 67 + .match = cgroup_mt_v1, 68 + .matchsize = sizeof(struct xt_cgroup_info_v1), 69 + .destroy = cgroup_mt_destroy_v1, 113 70 .me = THIS_MODULE, 114 71 .hooks = (1 << NF_INET_LOCAL_OUT) | 115 72 (1 << NF_INET_POST_ROUTING) |