Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.14-rc7 145 lines 3.7 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#include <linux/skbuff.h> 16#include <linux/module.h> 17#include <linux/netfilter/x_tables.h> 18#include <linux/netfilter/xt_cgroup.h> 19#include <net/sock.h> 20 21MODULE_LICENSE("GPL"); 22MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>"); 23MODULE_DESCRIPTION("Xtables: process control group matching"); 24MODULE_ALIAS("ipt_cgroup"); 25MODULE_ALIAS("ip6t_cgroup"); 26 27static int cgroup_mt_check_v0(const struct xt_mtchk_param *par) 28{ 29 struct xt_cgroup_info_v0 *info = par->matchinfo; 30 31 if (info->invert & ~1) 32 return -EINVAL; 33 34 return 0; 35} 36 37static 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 68static bool 69cgroup_mt_v0(const struct sk_buff *skb, struct xt_action_param *par) 70{ 71 const struct xt_cgroup_info_v0 *info = par->matchinfo; 72 73 if (skb->sk == NULL || !sk_fullsock(skb->sk)) 74 return false; 75 76 return (info->id == sock_cgroup_classid(&skb->sk->sk_cgrp_data)) ^ 77 info->invert; 78} 79 80static bool cgroup_mt_v1(const struct sk_buff *skb, struct xt_action_param *par) 81{ 82 const struct xt_cgroup_info_v1 *info = par->matchinfo; 83 struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data; 84 struct cgroup *ancestor = info->priv; 85 86 if (!skb->sk || !sk_fullsock(skb->sk)) 87 return false; 88 89 if (ancestor) 90 return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^ 91 info->invert_path; 92 else 93 return (info->classid == sock_cgroup_classid(skcd)) ^ 94 info->invert_classid; 95} 96 97static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par) 98{ 99 struct xt_cgroup_info_v1 *info = par->matchinfo; 100 101 if (info->priv) 102 cgroup_put(info->priv); 103} 104 105static struct xt_match cgroup_mt_reg[] __read_mostly = { 106 { 107 .name = "cgroup", 108 .revision = 0, 109 .family = NFPROTO_UNSPEC, 110 .checkentry = cgroup_mt_check_v0, 111 .match = cgroup_mt_v0, 112 .matchsize = sizeof(struct xt_cgroup_info_v0), 113 .me = THIS_MODULE, 114 .hooks = (1 << NF_INET_LOCAL_OUT) | 115 (1 << NF_INET_POST_ROUTING) | 116 (1 << NF_INET_LOCAL_IN), 117 }, 118 { 119 .name = "cgroup", 120 .revision = 1, 121 .family = NFPROTO_UNSPEC, 122 .checkentry = cgroup_mt_check_v1, 123 .match = cgroup_mt_v1, 124 .matchsize = sizeof(struct xt_cgroup_info_v1), 125 .usersize = offsetof(struct xt_cgroup_info_v1, priv), 126 .destroy = cgroup_mt_destroy_v1, 127 .me = THIS_MODULE, 128 .hooks = (1 << NF_INET_LOCAL_OUT) | 129 (1 << NF_INET_POST_ROUTING) | 130 (1 << NF_INET_LOCAL_IN), 131 }, 132}; 133 134static int __init cgroup_mt_init(void) 135{ 136 return xt_register_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg)); 137} 138 139static void __exit cgroup_mt_exit(void) 140{ 141 xt_unregister_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg)); 142} 143 144module_init(cgroup_mt_init); 145module_exit(cgroup_mt_exit);