1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Kernel module to match various things tied to sockets associated with 4 * locally generated outgoing packets. 5 * 6 * (C) 2000 Marc Boucher <marc@mbsi.ca> 7 * 8 * Copyright © CC Computer Consultants GmbH, 2007 - 2008 9 */ 10 #include <linux/module.h> 11 #include <linux/skbuff.h> 12 #include <linux/file.h> 13 #include <linux/cred.h> 14 15 #include <net/sock.h> 16 #include <net/inet_sock.h> 17 #include <linux/netfilter/x_tables.h> 18 #include <linux/netfilter/xt_owner.h> 19 20 static int owner_check(const struct xt_mtchk_param *par) 21 { 22 struct xt_owner_match_info *info = par->matchinfo; 23 struct net *net = par->net; 24 25 /* Only allow the common case where the userns of the writer 26 * matches the userns of the network namespace. 27 */ 28 if ((info->match & (XT_OWNER_UID|XT_OWNER_GID)) && 29 (current_user_ns() != net->user_ns)) 30 return -EINVAL; 31 32 /* Ensure the uids are valid */ 33 if (info->match & XT_OWNER_UID) { 34 kuid_t uid_min = make_kuid(net->user_ns, info->uid_min); 35 kuid_t uid_max = make_kuid(net->user_ns, info->uid_max); 36 37 if (!uid_valid(uid_min) || !uid_valid(uid_max) || 38 (info->uid_max < info->uid_min) || 39 uid_lt(uid_max, uid_min)) { 40 return -EINVAL; 41 } 42 } 43 44 /* Ensure the gids are valid */ 45 if (info->match & XT_OWNER_GID) { 46 kgid_t gid_min = make_kgid(net->user_ns, info->gid_min); 47 kgid_t gid_max = make_kgid(net->user_ns, info->gid_max); 48 49 if (!gid_valid(gid_min) || !gid_valid(gid_max) || 50 (info->gid_max < info->gid_min) || 51 gid_lt(gid_max, gid_min)) { 52 return -EINVAL; 53 } 54 } 55 56 return 0; 57 } 58 59 static bool 60 owner_mt(const struct sk_buff *skb, struct xt_action_param *par) 61 { 62 const struct xt_owner_match_info *info = par->matchinfo; 63 const struct file *filp; 64 struct sock *sk = skb_to_full_sk(skb); 65 struct net *net = xt_net(par); 66 67 if (!sk || !sk->sk_socket || !net_eq(net, sock_net(sk))) 68 return (info->match ^ info->invert) == 0; 69 else if (info->match & info->invert & XT_OWNER_SOCKET) 70 /* 71 * Socket exists but user wanted ! --socket-exists. 72 * (Single ampersands intended.) 73 */ 74 return false; 75 76 filp = sk->sk_socket->file; 77 if (filp == NULL) 78 return ((info->match ^ info->invert) & 79 (XT_OWNER_UID | XT_OWNER_GID)) == 0; 80 81 if (info->match & XT_OWNER_UID) { 82 kuid_t uid_min = make_kuid(net->user_ns, info->uid_min); 83 kuid_t uid_max = make_kuid(net->user_ns, info->uid_max); 84 if ((uid_gte(filp->f_cred->fsuid, uid_min) && 85 uid_lte(filp->f_cred->fsuid, uid_max)) ^ 86 !(info->invert & XT_OWNER_UID)) 87 return false; 88 } 89 90 if (info->match & XT_OWNER_GID) { 91 kgid_t gid_min = make_kgid(net->user_ns, info->gid_min); 92 kgid_t gid_max = make_kgid(net->user_ns, info->gid_max); 93 if ((gid_gte(filp->f_cred->fsgid, gid_min) && 94 gid_lte(filp->f_cred->fsgid, gid_max)) ^ 95 !(info->invert & XT_OWNER_GID)) 96 return false; 97 } 98 99 return true; 100 } 101 102 static struct xt_match owner_mt_reg __read_mostly = { 103 .name = "owner", 104 .revision = 1, 105 .family = NFPROTO_UNSPEC, 106 .checkentry = owner_check, 107 .match = owner_mt, 108 .matchsize = sizeof(struct xt_owner_match_info), 109 .hooks = (1 << NF_INET_LOCAL_OUT) | 110 (1 << NF_INET_POST_ROUTING), 111 .me = THIS_MODULE, 112 }; 113 114 static int __init owner_mt_init(void) 115 { 116 return xt_register_match(&owner_mt_reg); 117 } 118 119 static void __exit owner_mt_exit(void) 120 { 121 xt_unregister_match(&owner_mt_reg); 122 } 123 124 module_init(owner_mt_init); 125 module_exit(owner_mt_exit); 126 MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>"); 127 MODULE_DESCRIPTION("Xtables: socket owner matching"); 128 MODULE_LICENSE("GPL"); 129 MODULE_ALIAS("ipt_owner"); 130 MODULE_ALIAS("ip6t_owner"); 131