Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.18-rc4 148 lines 3.8 kB view raw
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 15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16 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 23MODULE_LICENSE("GPL"); 24MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>"); 25MODULE_DESCRIPTION("Xtables: process control group matching"); 26MODULE_ALIAS("ipt_cgroup"); 27MODULE_ALIAS("ip6t_cgroup"); 28 29static int cgroup_mt_check_v0(const struct xt_mtchk_param *par) 30{ 31 struct xt_cgroup_info_v0 *info = par->matchinfo; 32 33 if (info->invert & ~1) 34 return -EINVAL; 35 36 return 0; 37} 38 39static 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) { 53 pr_info_ratelimited("path and classid specified\n"); 54 return -EINVAL; 55 } 56 57 info->priv = NULL; 58 if (info->has_path) { 59 cgrp = cgroup_get_from_path(info->path); 60 if (IS_ERR(cgrp)) { 61 pr_info_ratelimited("invalid path, errno=%ld\n", 62 PTR_ERR(cgrp)); 63 return -EINVAL; 64 } 65 info->priv = cgrp; 66 } 67 68 return 0; 69} 70 71static bool 72cgroup_mt_v0(const struct sk_buff *skb, struct xt_action_param *par) 73{ 74 const struct xt_cgroup_info_v0 *info = par->matchinfo; 75 76 if (skb->sk == NULL || !sk_fullsock(skb->sk)) 77 return false; 78 79 return (info->id == sock_cgroup_classid(&skb->sk->sk_cgrp_data)) ^ 80 info->invert; 81} 82 83static bool cgroup_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) 84{ 85 const struct xt_cgroup_info_v1 *info = par->matchinfo; 86 struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data; 87 struct cgroup *ancestor = info->priv; 88 89 if (!skb->sk || !sk_fullsock(skb->sk)) 90 return false; 91 92 if (ancestor) 93 return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^ 94 info->invert_path; 95 else 96 return (info->classid == sock_cgroup_classid(skcd)) ^ 97 info->invert_classid; 98} 99 100static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par) 101{ 102 struct xt_cgroup_info_v1 *info = par->matchinfo; 103 104 if (info->priv) 105 cgroup_put(info->priv); 106} 107 108static struct xt_match cgroup_mt_reg[] __read_mostly = { 109 { 110 .name = "cgroup", 111 .revision = 0, 112 .family = NFPROTO_UNSPEC, 113 .checkentry = cgroup_mt_check_v0, 114 .match = cgroup_mt_v0, 115 .matchsize = sizeof(struct xt_cgroup_info_v0), 116 .me = THIS_MODULE, 117 .hooks = (1 << NF_INET_LOCAL_OUT) | 118 (1 << NF_INET_POST_ROUTING) | 119 (1 << NF_INET_LOCAL_IN), 120 }, 121 { 122 .name = "cgroup", 123 .revision = 1, 124 .family = NFPROTO_UNSPEC, 125 .checkentry = cgroup_mt_check_v1, 126 .match = cgroup_mt_v1, 127 .matchsize = sizeof(struct xt_cgroup_info_v1), 128 .usersize = offsetof(struct xt_cgroup_info_v1, priv), 129 .destroy = cgroup_mt_destroy_v1, 130 .me = THIS_MODULE, 131 .hooks = (1 << NF_INET_LOCAL_OUT) | 132 (1 << NF_INET_POST_ROUTING) | 133 (1 << NF_INET_LOCAL_IN), 134 }, 135}; 136 137static int __init cgroup_mt_init(void) 138{ 139 return xt_register_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg)); 140} 141 142static void __exit cgroup_mt_exit(void) 143{ 144 xt_unregister_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg)); 145} 146 147module_init(cgroup_mt_init); 148module_exit(cgroup_mt_exit);