Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Xtables module to match the process control group. |
| 3 | * |
| 4 | * Might be used to implement individual "per-application" firewall |
| 5 | * policies in contrast to global policies based on control groups. |
| 6 | * Matching is based upon processes tagged to net_cls' classid marker. |
| 7 | * |
| 8 | * (C) 2013 Daniel Borkmann <dborkman@redhat.com> |
| 9 | * |
| 10 | * This program is free software; you can redistribute it and/or modify |
| 11 | * it under the terms of the GNU General Public License version 2 as |
| 12 | * published by the Free Software Foundation. |
| 13 | */ |
| 14 | |
Florian Westphal | b260664 | 2018-02-09 15:52:07 +0100 | [diff] [blame] | 15 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| 16 | |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 17 | #include <linux/skbuff.h> |
| 18 | #include <linux/module.h> |
| 19 | #include <linux/netfilter/x_tables.h> |
| 20 | #include <linux/netfilter/xt_cgroup.h> |
| 21 | #include <net/sock.h> |
| 22 | |
| 23 | MODULE_LICENSE("GPL"); |
| 24 | MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>"); |
| 25 | MODULE_DESCRIPTION("Xtables: process control group matching"); |
| 26 | MODULE_ALIAS("ipt_cgroup"); |
| 27 | MODULE_ALIAS("ip6t_cgroup"); |
| 28 | |
Tejun Heo | 4ec8ff0 | 2015-12-07 17:38:54 -0500 | [diff] [blame] | 29 | static int cgroup_mt_check_v0(const struct xt_mtchk_param *par) |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 30 | { |
Tejun Heo | 4ec8ff0 | 2015-12-07 17:38:54 -0500 | [diff] [blame] | 31 | struct xt_cgroup_info_v0 *info = par->matchinfo; |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 32 | |
| 33 | if (info->invert & ~1) |
| 34 | return -EINVAL; |
| 35 | |
Daniel Borkmann | caa8ad9 | 2014-08-18 15:46:28 +0200 | [diff] [blame] | 36 | return 0; |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 37 | } |
| 38 | |
Tejun Heo | c38c459 | 2015-12-07 17:38:55 -0500 | [diff] [blame] | 39 | static int cgroup_mt_check_v1(const struct xt_mtchk_param *par) |
| 40 | { |
| 41 | struct xt_cgroup_info_v1 *info = par->matchinfo; |
| 42 | struct cgroup *cgrp; |
| 43 | |
| 44 | if ((info->invert_path & ~1) || (info->invert_classid & ~1)) |
| 45 | return -EINVAL; |
| 46 | |
| 47 | if (!info->has_path && !info->has_classid) { |
| 48 | pr_info("xt_cgroup: no path or classid specified\n"); |
| 49 | return -EINVAL; |
| 50 | } |
| 51 | |
| 52 | if (info->has_path && info->has_classid) { |
Florian Westphal | b260664 | 2018-02-09 15:52:07 +0100 | [diff] [blame] | 53 | pr_info_ratelimited("path and classid specified\n"); |
Tejun Heo | c38c459 | 2015-12-07 17:38:55 -0500 | [diff] [blame] | 54 | return -EINVAL; |
| 55 | } |
| 56 | |
Cong Wang | ba7cd5d | 2018-01-31 15:02:47 -0800 | [diff] [blame] | 57 | info->priv = NULL; |
Tejun Heo | c38c459 | 2015-12-07 17:38:55 -0500 | [diff] [blame] | 58 | if (info->has_path) { |
| 59 | cgrp = cgroup_get_from_path(info->path); |
| 60 | if (IS_ERR(cgrp)) { |
Florian Westphal | b260664 | 2018-02-09 15:52:07 +0100 | [diff] [blame] | 61 | pr_info_ratelimited("invalid path, errno=%ld\n", |
| 62 | PTR_ERR(cgrp)); |
Tejun Heo | c38c459 | 2015-12-07 17:38:55 -0500 | [diff] [blame] | 63 | return -EINVAL; |
| 64 | } |
| 65 | info->priv = cgrp; |
| 66 | } |
| 67 | |
| 68 | return 0; |
| 69 | } |
| 70 | |
Pablo Neira Ayuso | 0d70496 | 2018-09-04 12:07:55 +0200 | [diff] [blame] | 71 | static int cgroup_mt_check_v2(const struct xt_mtchk_param *par) |
| 72 | { |
| 73 | struct xt_cgroup_info_v2 *info = par->matchinfo; |
| 74 | struct cgroup *cgrp; |
| 75 | |
| 76 | if ((info->invert_path & ~1) || (info->invert_classid & ~1)) |
| 77 | return -EINVAL; |
| 78 | |
| 79 | if (!info->has_path && !info->has_classid) { |
| 80 | pr_info("xt_cgroup: no path or classid specified\n"); |
| 81 | return -EINVAL; |
| 82 | } |
| 83 | |
| 84 | if (info->has_path && info->has_classid) { |
| 85 | pr_info_ratelimited("path and classid specified\n"); |
| 86 | return -EINVAL; |
| 87 | } |
| 88 | |
| 89 | info->priv = NULL; |
| 90 | if (info->has_path) { |
| 91 | cgrp = cgroup_get_from_path(info->path); |
| 92 | if (IS_ERR(cgrp)) { |
| 93 | pr_info_ratelimited("invalid path, errno=%ld\n", |
| 94 | PTR_ERR(cgrp)); |
| 95 | return -EINVAL; |
| 96 | } |
| 97 | info->priv = cgrp; |
| 98 | } |
| 99 | |
| 100 | return 0; |
| 101 | } |
| 102 | |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 103 | static bool |
Tejun Heo | 4ec8ff0 | 2015-12-07 17:38:54 -0500 | [diff] [blame] | 104 | cgroup_mt_v0(const struct sk_buff *skb, struct xt_action_param *par) |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 105 | { |
Tejun Heo | 4ec8ff0 | 2015-12-07 17:38:54 -0500 | [diff] [blame] | 106 | const struct xt_cgroup_info_v0 *info = par->matchinfo; |
Flavio Leitner | f564650 | 2018-06-27 10:34:25 -0300 | [diff] [blame] | 107 | struct sock *sk = skb->sk; |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 108 | |
Flavio Leitner | f564650 | 2018-06-27 10:34:25 -0300 | [diff] [blame] | 109 | if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk))) |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 110 | return false; |
| 111 | |
Tejun Heo | 2a56a1f | 2015-12-07 17:38:52 -0500 | [diff] [blame] | 112 | return (info->id == sock_cgroup_classid(&skb->sk->sk_cgrp_data)) ^ |
| 113 | info->invert; |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 114 | } |
| 115 | |
Tejun Heo | c38c459 | 2015-12-07 17:38:55 -0500 | [diff] [blame] | 116 | static bool cgroup_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) |
| 117 | { |
| 118 | const struct xt_cgroup_info_v1 *info = par->matchinfo; |
| 119 | struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data; |
| 120 | struct cgroup *ancestor = info->priv; |
Flavio Leitner | f564650 | 2018-06-27 10:34:25 -0300 | [diff] [blame] | 121 | struct sock *sk = skb->sk; |
Tejun Heo | c38c459 | 2015-12-07 17:38:55 -0500 | [diff] [blame] | 122 | |
Flavio Leitner | f564650 | 2018-06-27 10:34:25 -0300 | [diff] [blame] | 123 | if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk))) |
Tejun Heo | c38c459 | 2015-12-07 17:38:55 -0500 | [diff] [blame] | 124 | return false; |
| 125 | |
| 126 | if (ancestor) |
| 127 | return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^ |
| 128 | info->invert_path; |
| 129 | else |
| 130 | return (info->classid == sock_cgroup_classid(skcd)) ^ |
| 131 | info->invert_classid; |
| 132 | } |
| 133 | |
Pablo Neira Ayuso | 0d70496 | 2018-09-04 12:07:55 +0200 | [diff] [blame] | 134 | static bool cgroup_mt_v2(const struct sk_buff *skb, struct xt_action_param *par) |
| 135 | { |
| 136 | const struct xt_cgroup_info_v2 *info = par->matchinfo; |
| 137 | struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data; |
| 138 | struct cgroup *ancestor = info->priv; |
| 139 | struct sock *sk = skb->sk; |
| 140 | |
| 141 | if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk))) |
| 142 | return false; |
| 143 | |
| 144 | if (ancestor) |
| 145 | return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^ |
| 146 | info->invert_path; |
| 147 | else |
| 148 | return (info->classid == sock_cgroup_classid(skcd)) ^ |
| 149 | info->invert_classid; |
| 150 | } |
| 151 | |
Tejun Heo | c38c459 | 2015-12-07 17:38:55 -0500 | [diff] [blame] | 152 | static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par) |
| 153 | { |
| 154 | struct xt_cgroup_info_v1 *info = par->matchinfo; |
| 155 | |
| 156 | if (info->priv) |
| 157 | cgroup_put(info->priv); |
| 158 | } |
| 159 | |
Pablo Neira Ayuso | 0d70496 | 2018-09-04 12:07:55 +0200 | [diff] [blame] | 160 | static void cgroup_mt_destroy_v2(const struct xt_mtdtor_param *par) |
| 161 | { |
| 162 | struct xt_cgroup_info_v2 *info = par->matchinfo; |
| 163 | |
| 164 | if (info->priv) |
| 165 | cgroup_put(info->priv); |
| 166 | } |
| 167 | |
Tejun Heo | 4ec8ff0 | 2015-12-07 17:38:54 -0500 | [diff] [blame] | 168 | static struct xt_match cgroup_mt_reg[] __read_mostly = { |
| 169 | { |
| 170 | .name = "cgroup", |
| 171 | .revision = 0, |
| 172 | .family = NFPROTO_UNSPEC, |
| 173 | .checkentry = cgroup_mt_check_v0, |
| 174 | .match = cgroup_mt_v0, |
| 175 | .matchsize = sizeof(struct xt_cgroup_info_v0), |
| 176 | .me = THIS_MODULE, |
| 177 | .hooks = (1 << NF_INET_LOCAL_OUT) | |
| 178 | (1 << NF_INET_POST_ROUTING) | |
| 179 | (1 << NF_INET_LOCAL_IN), |
| 180 | }, |
Tejun Heo | c38c459 | 2015-12-07 17:38:55 -0500 | [diff] [blame] | 181 | { |
| 182 | .name = "cgroup", |
| 183 | .revision = 1, |
| 184 | .family = NFPROTO_UNSPEC, |
| 185 | .checkentry = cgroup_mt_check_v1, |
| 186 | .match = cgroup_mt_v1, |
| 187 | .matchsize = sizeof(struct xt_cgroup_info_v1), |
Willem de Bruijn | ec23189 | 2017-01-02 17:19:46 -0500 | [diff] [blame] | 188 | .usersize = offsetof(struct xt_cgroup_info_v1, priv), |
Tejun Heo | c38c459 | 2015-12-07 17:38:55 -0500 | [diff] [blame] | 189 | .destroy = cgroup_mt_destroy_v1, |
| 190 | .me = THIS_MODULE, |
| 191 | .hooks = (1 << NF_INET_LOCAL_OUT) | |
| 192 | (1 << NF_INET_POST_ROUTING) | |
| 193 | (1 << NF_INET_LOCAL_IN), |
| 194 | }, |
Pablo Neira Ayuso | 0d70496 | 2018-09-04 12:07:55 +0200 | [diff] [blame] | 195 | { |
| 196 | .name = "cgroup", |
| 197 | .revision = 2, |
| 198 | .family = NFPROTO_UNSPEC, |
| 199 | .checkentry = cgroup_mt_check_v2, |
| 200 | .match = cgroup_mt_v2, |
| 201 | .matchsize = sizeof(struct xt_cgroup_info_v2), |
| 202 | .usersize = offsetof(struct xt_cgroup_info_v2, priv), |
| 203 | .destroy = cgroup_mt_destroy_v2, |
| 204 | .me = THIS_MODULE, |
| 205 | .hooks = (1 << NF_INET_LOCAL_OUT) | |
| 206 | (1 << NF_INET_POST_ROUTING) | |
| 207 | (1 << NF_INET_LOCAL_IN), |
| 208 | }, |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 209 | }; |
| 210 | |
| 211 | static int __init cgroup_mt_init(void) |
| 212 | { |
Tejun Heo | 4ec8ff0 | 2015-12-07 17:38:54 -0500 | [diff] [blame] | 213 | return xt_register_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg)); |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 214 | } |
| 215 | |
| 216 | static void __exit cgroup_mt_exit(void) |
| 217 | { |
Tejun Heo | 4ec8ff0 | 2015-12-07 17:38:54 -0500 | [diff] [blame] | 218 | xt_unregister_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg)); |
Daniel Borkmann | 82a3713 | 2013-12-29 18:27:12 +0100 | [diff] [blame] | 219 | } |
| 220 | |
| 221 | module_init(cgroup_mt_init); |
| 222 | module_exit(cgroup_mt_exit); |