xref: /openbmc/linux/net/netfilter/xt_owner.c (revision 1417b719)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20265ab44SJan Engelhardt /*
30265ab44SJan Engelhardt  * Kernel module to match various things tied to sockets associated with
40265ab44SJan Engelhardt  * locally generated outgoing packets.
50265ab44SJan Engelhardt  *
60265ab44SJan Engelhardt  * (C) 2000 Marc Boucher <marc@mbsi.ca>
70265ab44SJan Engelhardt  *
8edc26f7aSJan Engelhardt  * Copyright © CC Computer Consultants GmbH, 2007 - 2008
90265ab44SJan Engelhardt  */
100265ab44SJan Engelhardt #include <linux/module.h>
110265ab44SJan Engelhardt #include <linux/skbuff.h>
120265ab44SJan Engelhardt #include <linux/file.h>
135b825c3aSIngo Molnar #include <linux/cred.h>
145b825c3aSIngo Molnar 
150265ab44SJan Engelhardt #include <net/sock.h>
16fdd723e2SEric Dumazet #include <net/inet_sock.h>
170265ab44SJan Engelhardt #include <linux/netfilter/x_tables.h>
180265ab44SJan Engelhardt #include <linux/netfilter/xt_owner.h>
190265ab44SJan Engelhardt 
owner_check(const struct xt_mtchk_param * par)2026711a79SEric W. Biederman static int owner_check(const struct xt_mtchk_param *par)
2126711a79SEric W. Biederman {
2226711a79SEric W. Biederman 	struct xt_owner_match_info *info = par->matchinfo;
239847371aSEric W. Biederman 	struct net *net = par->net;
2426711a79SEric W. Biederman 
259911c113SPablo Neira Ayuso 	if (info->match & ~XT_OWNER_MASK)
269911c113SPablo Neira Ayuso 		return -EINVAL;
279911c113SPablo Neira Ayuso 
289847371aSEric W. Biederman 	/* Only allow the common case where the userns of the writer
299847371aSEric W. Biederman 	 * matches the userns of the network namespace.
309847371aSEric W. Biederman 	 */
3126711a79SEric W. Biederman 	if ((info->match & (XT_OWNER_UID|XT_OWNER_GID)) &&
329847371aSEric W. Biederman 	    (current_user_ns() != net->user_ns))
3326711a79SEric W. Biederman 		return -EINVAL;
349847371aSEric W. Biederman 
359847371aSEric W. Biederman 	/* Ensure the uids are valid */
369847371aSEric W. Biederman 	if (info->match & XT_OWNER_UID) {
379847371aSEric W. Biederman 		kuid_t uid_min = make_kuid(net->user_ns, info->uid_min);
389847371aSEric W. Biederman 		kuid_t uid_max = make_kuid(net->user_ns, info->uid_max);
399847371aSEric W. Biederman 
409847371aSEric W. Biederman 		if (!uid_valid(uid_min) || !uid_valid(uid_max) ||
419847371aSEric W. Biederman 		    (info->uid_max < info->uid_min) ||
429847371aSEric W. Biederman 		    uid_lt(uid_max, uid_min)) {
439847371aSEric W. Biederman 			return -EINVAL;
449847371aSEric W. Biederman 		}
459847371aSEric W. Biederman 	}
469847371aSEric W. Biederman 
479847371aSEric W. Biederman 	/* Ensure the gids are valid */
489847371aSEric W. Biederman 	if (info->match & XT_OWNER_GID) {
499847371aSEric W. Biederman 		kgid_t gid_min = make_kgid(net->user_ns, info->gid_min);
509847371aSEric W. Biederman 		kgid_t gid_max = make_kgid(net->user_ns, info->gid_max);
519847371aSEric W. Biederman 
529847371aSEric W. Biederman 		if (!gid_valid(gid_min) || !gid_valid(gid_max) ||
539847371aSEric W. Biederman 		    (info->gid_max < info->gid_min) ||
549847371aSEric W. Biederman 		    gid_lt(gid_max, gid_min)) {
559847371aSEric W. Biederman 			return -EINVAL;
569847371aSEric W. Biederman 		}
579847371aSEric W. Biederman 	}
589847371aSEric W. Biederman 
5926711a79SEric W. Biederman 	return 0;
6026711a79SEric W. Biederman }
6126711a79SEric W. Biederman 
620265ab44SJan Engelhardt static bool
owner_mt(const struct sk_buff * skb,struct xt_action_param * par)6362fc8051SJan Engelhardt owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
640265ab44SJan Engelhardt {
65f7108a20SJan Engelhardt 	const struct xt_owner_match_info *info = par->matchinfo;
660265ab44SJan Engelhardt 	const struct file *filp;
67fdd723e2SEric Dumazet 	struct sock *sk = skb_to_full_sk(skb);
68613dbd95SPablo Neira Ayuso 	struct net *net = xt_net(par);
690265ab44SJan Engelhardt 
70f5646501SFlavio Leitner 	if (!sk || !sk->sk_socket || !net_eq(net, sock_net(sk)))
710265ab44SJan Engelhardt 		return (info->match ^ info->invert) == 0;
720265ab44SJan Engelhardt 	else if (info->match & info->invert & XT_OWNER_SOCKET)
730265ab44SJan Engelhardt 		/*
740265ab44SJan Engelhardt 		 * Socket exists but user wanted ! --socket-exists.
750265ab44SJan Engelhardt 		 * (Single ampersands intended.)
760265ab44SJan Engelhardt 		 */
770265ab44SJan Engelhardt 		return false;
780265ab44SJan Engelhardt 
79*1417b719SPhil Sutter 	read_lock_bh(&sk->sk_callback_lock);
80*1417b719SPhil Sutter 	filp = sk->sk_socket ? sk->sk_socket->file : NULL;
81*1417b719SPhil Sutter 	if (filp == NULL) {
82*1417b719SPhil Sutter 		read_unlock_bh(&sk->sk_callback_lock);
830265ab44SJan Engelhardt 		return ((info->match ^ info->invert) &
840265ab44SJan Engelhardt 		       (XT_OWNER_UID | XT_OWNER_GID)) == 0;
85*1417b719SPhil Sutter 	}
860265ab44SJan Engelhardt 
8726711a79SEric W. Biederman 	if (info->match & XT_OWNER_UID) {
889847371aSEric W. Biederman 		kuid_t uid_min = make_kuid(net->user_ns, info->uid_min);
899847371aSEric W. Biederman 		kuid_t uid_max = make_kuid(net->user_ns, info->uid_max);
9026711a79SEric W. Biederman 		if ((uid_gte(filp->f_cred->fsuid, uid_min) &&
9126711a79SEric W. Biederman 		     uid_lte(filp->f_cred->fsuid, uid_max)) ^
92*1417b719SPhil Sutter 		    !(info->invert & XT_OWNER_UID)) {
93*1417b719SPhil Sutter 			read_unlock_bh(&sk->sk_callback_lock);
940265ab44SJan Engelhardt 			return false;
9526711a79SEric W. Biederman 		}
96*1417b719SPhil Sutter 	}
970265ab44SJan Engelhardt 
9826711a79SEric W. Biederman 	if (info->match & XT_OWNER_GID) {
99ea6cc2fdSLukasz Pawelczyk 		unsigned int i, match = false;
1009847371aSEric W. Biederman 		kgid_t gid_min = make_kgid(net->user_ns, info->gid_min);
1019847371aSEric W. Biederman 		kgid_t gid_max = make_kgid(net->user_ns, info->gid_max);
102ea6cc2fdSLukasz Pawelczyk 		struct group_info *gi = filp->f_cred->group_info;
103ea6cc2fdSLukasz Pawelczyk 
104ea6cc2fdSLukasz Pawelczyk 		if (gid_gte(filp->f_cred->fsgid, gid_min) &&
105ea6cc2fdSLukasz Pawelczyk 		    gid_lte(filp->f_cred->fsgid, gid_max))
106ea6cc2fdSLukasz Pawelczyk 			match = true;
107ea6cc2fdSLukasz Pawelczyk 
108ea6cc2fdSLukasz Pawelczyk 		if (!match && (info->match & XT_OWNER_SUPPL_GROUPS) && gi) {
109ea6cc2fdSLukasz Pawelczyk 			for (i = 0; i < gi->ngroups; ++i) {
110ea6cc2fdSLukasz Pawelczyk 				kgid_t group = gi->gid[i];
111ea6cc2fdSLukasz Pawelczyk 
112ea6cc2fdSLukasz Pawelczyk 				if (gid_gte(group, gid_min) &&
113ea6cc2fdSLukasz Pawelczyk 				    gid_lte(group, gid_max)) {
114ea6cc2fdSLukasz Pawelczyk 					match = true;
115ea6cc2fdSLukasz Pawelczyk 					break;
116ea6cc2fdSLukasz Pawelczyk 				}
117ea6cc2fdSLukasz Pawelczyk 			}
118ea6cc2fdSLukasz Pawelczyk 		}
119ea6cc2fdSLukasz Pawelczyk 
120*1417b719SPhil Sutter 		if (match ^ !(info->invert & XT_OWNER_GID)) {
121*1417b719SPhil Sutter 			read_unlock_bh(&sk->sk_callback_lock);
1220265ab44SJan Engelhardt 			return false;
12326711a79SEric W. Biederman 		}
124*1417b719SPhil Sutter 	}
1250265ab44SJan Engelhardt 
126*1417b719SPhil Sutter 	read_unlock_bh(&sk->sk_callback_lock);
1270265ab44SJan Engelhardt 	return true;
1280265ab44SJan Engelhardt }
1290265ab44SJan Engelhardt 
1306461caedSJan Engelhardt static struct xt_match owner_mt_reg __read_mostly = {
1310265ab44SJan Engelhardt 	.name       = "owner",
1320265ab44SJan Engelhardt 	.revision   = 1,
133ab4f21e6SJan Engelhardt 	.family     = NFPROTO_UNSPEC,
13426711a79SEric W. Biederman 	.checkentry = owner_check,
1350265ab44SJan Engelhardt 	.match      = owner_mt,
1360265ab44SJan Engelhardt 	.matchsize  = sizeof(struct xt_owner_match_info),
1370265ab44SJan Engelhardt 	.hooks      = (1 << NF_INET_LOCAL_OUT) |
1380265ab44SJan Engelhardt 	              (1 << NF_INET_POST_ROUTING),
1390265ab44SJan Engelhardt 	.me         = THIS_MODULE,
1400265ab44SJan Engelhardt };
1410265ab44SJan Engelhardt 
owner_mt_init(void)1420265ab44SJan Engelhardt static int __init owner_mt_init(void)
1430265ab44SJan Engelhardt {
1446461caedSJan Engelhardt 	return xt_register_match(&owner_mt_reg);
1450265ab44SJan Engelhardt }
1460265ab44SJan Engelhardt 
owner_mt_exit(void)1470265ab44SJan Engelhardt static void __exit owner_mt_exit(void)
1480265ab44SJan Engelhardt {
1496461caedSJan Engelhardt 	xt_unregister_match(&owner_mt_reg);
1500265ab44SJan Engelhardt }
1510265ab44SJan Engelhardt 
1520265ab44SJan Engelhardt module_init(owner_mt_init);
1530265ab44SJan Engelhardt module_exit(owner_mt_exit);
1546461caedSJan Engelhardt MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
1552ae15b64SJan Engelhardt MODULE_DESCRIPTION("Xtables: socket owner matching");
1560265ab44SJan Engelhardt MODULE_LICENSE("GPL");
1570265ab44SJan Engelhardt MODULE_ALIAS("ipt_owner");
1580265ab44SJan Engelhardt MODULE_ALIAS("ip6t_owner");
159