Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Xtables module to match the process control group.
0004  *
0005  * Might be used to implement individual "per-application" firewall
0006  * policies in contrast to global policies based on control groups.
0007  * Matching is based upon processes tagged to net_cls' classid marker.
0008  *
0009  * (C) 2013 Daniel Borkmann <dborkman@redhat.com>
0010  */
0011 
0012 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0013 
0014 #include <linux/skbuff.h>
0015 #include <linux/module.h>
0016 #include <linux/netfilter/x_tables.h>
0017 #include <linux/netfilter/xt_cgroup.h>
0018 #include <net/sock.h>
0019 
0020 MODULE_LICENSE("GPL");
0021 MODULE_AUTHOR("Daniel Borkmann <dborkman@redhat.com>");
0022 MODULE_DESCRIPTION("Xtables: process control group matching");
0023 MODULE_ALIAS("ipt_cgroup");
0024 MODULE_ALIAS("ip6t_cgroup");
0025 
0026 static int cgroup_mt_check_v0(const struct xt_mtchk_param *par)
0027 {
0028     struct xt_cgroup_info_v0 *info = par->matchinfo;
0029 
0030     if (info->invert & ~1)
0031         return -EINVAL;
0032 
0033     return 0;
0034 }
0035 
0036 static int cgroup_mt_check_v1(const struct xt_mtchk_param *par)
0037 {
0038     struct xt_cgroup_info_v1 *info = par->matchinfo;
0039     struct cgroup *cgrp;
0040 
0041     if ((info->invert_path & ~1) || (info->invert_classid & ~1))
0042         return -EINVAL;
0043 
0044     if (!info->has_path && !info->has_classid) {
0045         pr_info("xt_cgroup: no path or classid specified\n");
0046         return -EINVAL;
0047     }
0048 
0049     if (info->has_path && info->has_classid) {
0050         pr_info_ratelimited("path and classid specified\n");
0051         return -EINVAL;
0052     }
0053 
0054     info->priv = NULL;
0055     if (info->has_path) {
0056         cgrp = cgroup_get_from_path(info->path);
0057         if (IS_ERR(cgrp)) {
0058             pr_info_ratelimited("invalid path, errno=%ld\n",
0059                         PTR_ERR(cgrp));
0060             return -EINVAL;
0061         }
0062         info->priv = cgrp;
0063     }
0064 
0065     return 0;
0066 }
0067 
0068 static int cgroup_mt_check_v2(const struct xt_mtchk_param *par)
0069 {
0070     struct xt_cgroup_info_v2 *info = par->matchinfo;
0071     struct cgroup *cgrp;
0072 
0073     if ((info->invert_path & ~1) || (info->invert_classid & ~1))
0074         return -EINVAL;
0075 
0076     if (!info->has_path && !info->has_classid) {
0077         pr_info("xt_cgroup: no path or classid specified\n");
0078         return -EINVAL;
0079     }
0080 
0081     if (info->has_path && info->has_classid) {
0082         pr_info_ratelimited("path and classid specified\n");
0083         return -EINVAL;
0084     }
0085 
0086     info->priv = NULL;
0087     if (info->has_path) {
0088         cgrp = cgroup_get_from_path(info->path);
0089         if (IS_ERR(cgrp)) {
0090             pr_info_ratelimited("invalid path, errno=%ld\n",
0091                         PTR_ERR(cgrp));
0092             return -EINVAL;
0093         }
0094         info->priv = cgrp;
0095     }
0096 
0097     return 0;
0098 }
0099 
0100 static bool
0101 cgroup_mt_v0(const struct sk_buff *skb, struct xt_action_param *par)
0102 {
0103     const struct xt_cgroup_info_v0 *info = par->matchinfo;
0104     struct sock *sk = skb->sk;
0105 
0106     if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk)))
0107         return false;
0108 
0109     return (info->id == sock_cgroup_classid(&skb->sk->sk_cgrp_data)) ^
0110         info->invert;
0111 }
0112 
0113 static bool cgroup_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
0114 {
0115     const struct xt_cgroup_info_v1 *info = par->matchinfo;
0116     struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data;
0117     struct cgroup *ancestor = info->priv;
0118     struct sock *sk = skb->sk;
0119 
0120     if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk)))
0121         return false;
0122 
0123     if (ancestor)
0124         return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^
0125             info->invert_path;
0126     else
0127         return (info->classid == sock_cgroup_classid(skcd)) ^
0128             info->invert_classid;
0129 }
0130 
0131 static bool cgroup_mt_v2(const struct sk_buff *skb, struct xt_action_param *par)
0132 {
0133     const struct xt_cgroup_info_v2 *info = par->matchinfo;
0134     struct sock_cgroup_data *skcd = &skb->sk->sk_cgrp_data;
0135     struct cgroup *ancestor = info->priv;
0136     struct sock *sk = skb->sk;
0137 
0138     if (!sk || !sk_fullsock(sk) || !net_eq(xt_net(par), sock_net(sk)))
0139         return false;
0140 
0141     if (ancestor)
0142         return cgroup_is_descendant(sock_cgroup_ptr(skcd), ancestor) ^
0143             info->invert_path;
0144     else
0145         return (info->classid == sock_cgroup_classid(skcd)) ^
0146             info->invert_classid;
0147 }
0148 
0149 static void cgroup_mt_destroy_v1(const struct xt_mtdtor_param *par)
0150 {
0151     struct xt_cgroup_info_v1 *info = par->matchinfo;
0152 
0153     if (info->priv)
0154         cgroup_put(info->priv);
0155 }
0156 
0157 static void cgroup_mt_destroy_v2(const struct xt_mtdtor_param *par)
0158 {
0159     struct xt_cgroup_info_v2 *info = par->matchinfo;
0160 
0161     if (info->priv)
0162         cgroup_put(info->priv);
0163 }
0164 
0165 static struct xt_match cgroup_mt_reg[] __read_mostly = {
0166     {
0167         .name       = "cgroup",
0168         .revision   = 0,
0169         .family     = NFPROTO_UNSPEC,
0170         .checkentry = cgroup_mt_check_v0,
0171         .match      = cgroup_mt_v0,
0172         .matchsize  = sizeof(struct xt_cgroup_info_v0),
0173         .me     = THIS_MODULE,
0174         .hooks      = (1 << NF_INET_LOCAL_OUT) |
0175                   (1 << NF_INET_POST_ROUTING) |
0176                   (1 << NF_INET_LOCAL_IN),
0177     },
0178     {
0179         .name       = "cgroup",
0180         .revision   = 1,
0181         .family     = NFPROTO_UNSPEC,
0182         .checkentry = cgroup_mt_check_v1,
0183         .match      = cgroup_mt_v1,
0184         .matchsize  = sizeof(struct xt_cgroup_info_v1),
0185         .usersize   = offsetof(struct xt_cgroup_info_v1, priv),
0186         .destroy    = cgroup_mt_destroy_v1,
0187         .me     = THIS_MODULE,
0188         .hooks      = (1 << NF_INET_LOCAL_OUT) |
0189                   (1 << NF_INET_POST_ROUTING) |
0190                   (1 << NF_INET_LOCAL_IN),
0191     },
0192     {
0193         .name       = "cgroup",
0194         .revision   = 2,
0195         .family     = NFPROTO_UNSPEC,
0196         .checkentry = cgroup_mt_check_v2,
0197         .match      = cgroup_mt_v2,
0198         .matchsize  = sizeof(struct xt_cgroup_info_v2),
0199         .usersize   = offsetof(struct xt_cgroup_info_v2, priv),
0200         .destroy    = cgroup_mt_destroy_v2,
0201         .me     = THIS_MODULE,
0202         .hooks      = (1 << NF_INET_LOCAL_OUT) |
0203                   (1 << NF_INET_POST_ROUTING) |
0204                   (1 << NF_INET_LOCAL_IN),
0205     },
0206 };
0207 
0208 static int __init cgroup_mt_init(void)
0209 {
0210     return xt_register_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg));
0211 }
0212 
0213 static void __exit cgroup_mt_exit(void)
0214 {
0215     xt_unregister_matches(cgroup_mt_reg, ARRAY_SIZE(cgroup_mt_reg));
0216 }
0217 
0218 module_init(cgroup_mt_init);
0219 module_exit(cgroup_mt_exit);