cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xt_cgroup.c (5583B)


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