Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Kernel module to match various things tied to sockets associated with
0004  * locally generated outgoing packets.
0005  *
0006  * (C) 2000 Marc Boucher <marc@mbsi.ca>
0007  *
0008  * Copyright © CC Computer Consultants GmbH, 2007 - 2008
0009  */
0010 #include <linux/module.h>
0011 #include <linux/skbuff.h>
0012 #include <linux/file.h>
0013 #include <linux/cred.h>
0014 
0015 #include <net/sock.h>
0016 #include <net/inet_sock.h>
0017 #include <linux/netfilter/x_tables.h>
0018 #include <linux/netfilter/xt_owner.h>
0019 
0020 static int owner_check(const struct xt_mtchk_param *par)
0021 {
0022     struct xt_owner_match_info *info = par->matchinfo;
0023     struct net *net = par->net;
0024 
0025     if (info->match & ~XT_OWNER_MASK)
0026         return -EINVAL;
0027 
0028     /* Only allow the common case where the userns of the writer
0029      * matches the userns of the network namespace.
0030      */
0031     if ((info->match & (XT_OWNER_UID|XT_OWNER_GID)) &&
0032         (current_user_ns() != net->user_ns))
0033         return -EINVAL;
0034 
0035     /* Ensure the uids are valid */
0036     if (info->match & XT_OWNER_UID) {
0037         kuid_t uid_min = make_kuid(net->user_ns, info->uid_min);
0038         kuid_t uid_max = make_kuid(net->user_ns, info->uid_max);
0039 
0040         if (!uid_valid(uid_min) || !uid_valid(uid_max) ||
0041             (info->uid_max < info->uid_min) ||
0042             uid_lt(uid_max, uid_min)) {
0043             return -EINVAL;
0044         }
0045     }
0046 
0047     /* Ensure the gids are valid */
0048     if (info->match & XT_OWNER_GID) {
0049         kgid_t gid_min = make_kgid(net->user_ns, info->gid_min);
0050         kgid_t gid_max = make_kgid(net->user_ns, info->gid_max);
0051 
0052         if (!gid_valid(gid_min) || !gid_valid(gid_max) ||
0053             (info->gid_max < info->gid_min) ||
0054             gid_lt(gid_max, gid_min)) {
0055             return -EINVAL;
0056         }
0057     }
0058 
0059     return 0;
0060 }
0061 
0062 static bool
0063 owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
0064 {
0065     const struct xt_owner_match_info *info = par->matchinfo;
0066     const struct file *filp;
0067     struct sock *sk = skb_to_full_sk(skb);
0068     struct net *net = xt_net(par);
0069 
0070     if (!sk || !sk->sk_socket || !net_eq(net, sock_net(sk)))
0071         return (info->match ^ info->invert) == 0;
0072     else if (info->match & info->invert & XT_OWNER_SOCKET)
0073         /*
0074          * Socket exists but user wanted ! --socket-exists.
0075          * (Single ampersands intended.)
0076          */
0077         return false;
0078 
0079     filp = sk->sk_socket->file;
0080     if (filp == NULL)
0081         return ((info->match ^ info->invert) &
0082                (XT_OWNER_UID | XT_OWNER_GID)) == 0;
0083 
0084     if (info->match & XT_OWNER_UID) {
0085         kuid_t uid_min = make_kuid(net->user_ns, info->uid_min);
0086         kuid_t uid_max = make_kuid(net->user_ns, info->uid_max);
0087         if ((uid_gte(filp->f_cred->fsuid, uid_min) &&
0088              uid_lte(filp->f_cred->fsuid, uid_max)) ^
0089             !(info->invert & XT_OWNER_UID))
0090             return false;
0091     }
0092 
0093     if (info->match & XT_OWNER_GID) {
0094         unsigned int i, match = false;
0095         kgid_t gid_min = make_kgid(net->user_ns, info->gid_min);
0096         kgid_t gid_max = make_kgid(net->user_ns, info->gid_max);
0097         struct group_info *gi = filp->f_cred->group_info;
0098 
0099         if (gid_gte(filp->f_cred->fsgid, gid_min) &&
0100             gid_lte(filp->f_cred->fsgid, gid_max))
0101             match = true;
0102 
0103         if (!match && (info->match & XT_OWNER_SUPPL_GROUPS) && gi) {
0104             for (i = 0; i < gi->ngroups; ++i) {
0105                 kgid_t group = gi->gid[i];
0106 
0107                 if (gid_gte(group, gid_min) &&
0108                     gid_lte(group, gid_max)) {
0109                     match = true;
0110                     break;
0111                 }
0112             }
0113         }
0114 
0115         if (match ^ !(info->invert & XT_OWNER_GID))
0116             return false;
0117     }
0118 
0119     return true;
0120 }
0121 
0122 static struct xt_match owner_mt_reg __read_mostly = {
0123     .name       = "owner",
0124     .revision   = 1,
0125     .family     = NFPROTO_UNSPEC,
0126     .checkentry = owner_check,
0127     .match      = owner_mt,
0128     .matchsize  = sizeof(struct xt_owner_match_info),
0129     .hooks      = (1 << NF_INET_LOCAL_OUT) |
0130                   (1 << NF_INET_POST_ROUTING),
0131     .me         = THIS_MODULE,
0132 };
0133 
0134 static int __init owner_mt_init(void)
0135 {
0136     return xt_register_match(&owner_mt_reg);
0137 }
0138 
0139 static void __exit owner_mt_exit(void)
0140 {
0141     xt_unregister_match(&owner_mt_reg);
0142 }
0143 
0144 module_init(owner_mt_init);
0145 module_exit(owner_mt_exit);
0146 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
0147 MODULE_DESCRIPTION("Xtables: socket owner matching");
0148 MODULE_LICENSE("GPL");
0149 MODULE_ALIAS("ipt_owner");
0150 MODULE_ALIAS("ip6t_owner");