xref: /linux/security/apparmor/af_inet.c (revision 8fefe68784ae1606e11a5c65c04167c3b95051a0)
14f0cafcbSJohn Johansen /* SPDX-License-Identifier: GPL-2.0-only */
24f0cafcbSJohn Johansen /*
34f0cafcbSJohn Johansen  * AppArmor security module
44f0cafcbSJohn Johansen  *
54f0cafcbSJohn Johansen  * This file contains AppArmor inet fine grained mediation
64f0cafcbSJohn Johansen  *
74f0cafcbSJohn Johansen  * Copyright 2024 Canonical Ltd.
84f0cafcbSJohn Johansen  *
94f0cafcbSJohn Johansen  */
104f0cafcbSJohn Johansen 
114f0cafcbSJohn Johansen #include <net/tcp_states.h>
124f0cafcbSJohn Johansen 
134f0cafcbSJohn Johansen #include "include/audit.h"
144f0cafcbSJohn Johansen #include "include/af_inet.h"
154f0cafcbSJohn Johansen #include "include/apparmor.h"
164f0cafcbSJohn Johansen #include "include/file.h"
174f0cafcbSJohn Johansen #include "include/label.h"
184f0cafcbSJohn Johansen #include "include/net.h"
194f0cafcbSJohn Johansen #include "include/path.h"
204f0cafcbSJohn Johansen #include "include/policy.h"
214f0cafcbSJohn Johansen #include "include/cred.h"
224f0cafcbSJohn Johansen 
234f0cafcbSJohn Johansen 
RULE_MEDIATES_SK(struct aa_ruleset * rules,const struct sock * sk)24*89ac6aa7SJohn Johansen static inline aa_state_t RULE_MEDIATES_SK(struct aa_ruleset *rules,
25*89ac6aa7SJohn Johansen 					  const struct sock *sk)
26*89ac6aa7SJohn Johansen {
27*89ac6aa7SJohn Johansen 	return RULE_MEDIATES_NET(rules);
28*89ac6aa7SJohn Johansen }
29*89ac6aa7SJohn Johansen 
30*89ac6aa7SJohn Johansen 
31*89ac6aa7SJohn Johansen enum addr_type {
32*89ac6aa7SJohn Johansen 	ADDR_LOCAL = 0,
33*89ac6aa7SJohn Johansen 	ADDR_LOCAL_PRIV	= 1,
34*89ac6aa7SJohn Johansen 	ADDR_REMOTE = 2,
35*89ac6aa7SJohn Johansen };
36*89ac6aa7SJohn Johansen 
37*89ac6aa7SJohn Johansen struct match_addr {
38*89ac6aa7SJohn Johansen 	const char *addrp;
39*89ac6aa7SJohn Johansen 	enum addr_type addrtype;
40*89ac6aa7SJohn Johansen 	int len;
41*89ac6aa7SJohn Johansen 	__be16 port;
42*89ac6aa7SJohn Johansen };
43*89ac6aa7SJohn Johansen 
44*89ac6aa7SJohn Johansen struct stored_match_addr {
45*89ac6aa7SJohn Johansen 	union {
46*89ac6aa7SJohn Johansen 		struct sockaddr addr;
47*89ac6aa7SJohn Johansen 		struct sockaddr_in addr4;
48*89ac6aa7SJohn Johansen 		struct sockaddr_in6 addr6;
49*89ac6aa7SJohn Johansen 	};
50*89ac6aa7SJohn Johansen 	int addrlen;
51*89ac6aa7SJohn Johansen 	struct match_addr maddr;
52*89ac6aa7SJohn Johansen };
53*89ac6aa7SJohn Johansen 
set_ad_create(struct apparmor_audit_data * ad,int family,int type,int protocol)54*89ac6aa7SJohn Johansen static void set_ad_create(struct apparmor_audit_data *ad,
55*89ac6aa7SJohn Johansen 			 int family, int type, int protocol)
56*89ac6aa7SJohn Johansen {
57*89ac6aa7SJohn Johansen 	ad->common.u.net->family = family;
58*89ac6aa7SJohn Johansen 	ad->net.type = type;
59*89ac6aa7SJohn Johansen 	ad->net.protocol = protocol;
60*89ac6aa7SJohn Johansen }
61*89ac6aa7SJohn Johansen 
set_ad_addr(struct apparmor_audit_data * ad,u16 family,bool source,struct match_addr * maddr)62*89ac6aa7SJohn Johansen static int set_ad_addr(struct apparmor_audit_data *ad,
63*89ac6aa7SJohn Johansen 		       u16 family, bool source, struct match_addr *maddr)
64*89ac6aa7SJohn Johansen {
65*89ac6aa7SJohn Johansen 	ad->common.u.net->family = family;
66*89ac6aa7SJohn Johansen 
67*89ac6aa7SJohn Johansen 	if (source) {
68*89ac6aa7SJohn Johansen 		ad->common.u.net->sport = maddr->port;
69*89ac6aa7SJohn Johansen 		if (maddr->addrp) {
70*89ac6aa7SJohn Johansen 			if (family == AF_INET)
71*89ac6aa7SJohn Johansen 				/* ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; */
72*89ac6aa7SJohn Johansen 				ad->common.u.net->v4info.saddr = *(__be32 *)maddr->addrp;
73*89ac6aa7SJohn Johansen 			else
74*89ac6aa7SJohn Johansen 				/* ad.u.net->v4info.saddr = addr6->sin6_addr.s6_addr; */
75*89ac6aa7SJohn Johansen 				ad->common.u.net->v6info.saddr = *(struct in6_addr *)maddr->addrp;
76*89ac6aa7SJohn Johansen 		}
77*89ac6aa7SJohn Johansen 	} else {
78*89ac6aa7SJohn Johansen 		ad->common.u.net->dport = maddr->port;
79*89ac6aa7SJohn Johansen 		if (maddr->addrp) {
80*89ac6aa7SJohn Johansen 			if (family == AF_INET)
81*89ac6aa7SJohn Johansen 				/* ad.u.net->v4info.saddr = addr4->sin_addr.s_addr; */
82*89ac6aa7SJohn Johansen 				ad->common.u.net->v4info.daddr = *(__be32 *)maddr->addrp;
83*89ac6aa7SJohn Johansen 			else
84*89ac6aa7SJohn Johansen 				/* ad.u.net->v4info.saddr = addr6->sin6_addr.s6_addr; */
85*89ac6aa7SJohn Johansen 				ad->common.u.net->v6info.daddr = *(struct in6_addr *)maddr->addrp;
86*89ac6aa7SJohn Johansen 		}
87*89ac6aa7SJohn Johansen 	}
88*89ac6aa7SJohn Johansen 	return 0;
89*89ac6aa7SJohn Johansen }
90*89ac6aa7SJohn Johansen 
91*89ac6aa7SJohn Johansen /* returns 0 on success
92*89ac6aa7SJohn Johansen * raw_port - if set raw_port (protocol) when SOCK_RAW */
map_addr(struct sockaddr * addr,int addrlen,u16 raw_port,enum addr_type addrtype,struct match_addr * maddr,struct apparmor_audit_data * ad)93*89ac6aa7SJohn Johansen static int map_addr(struct sockaddr *addr, int addrlen, u16 raw_port,
94*89ac6aa7SJohn Johansen 		    enum addr_type addrtype, struct match_addr *maddr,
95*89ac6aa7SJohn Johansen 		    struct apparmor_audit_data *ad)
96*89ac6aa7SJohn Johansen {
97*89ac6aa7SJohn Johansen 	struct sockaddr_in *addr4 = NULL;
98*89ac6aa7SJohn Johansen 	struct sockaddr_in6 *addr6 = NULL;
99*89ac6aa7SJohn Johansen 
100*89ac6aa7SJohn Johansen 	AA_BUG(!addr);
101*89ac6aa7SJohn Johansen 	AA_BUG(!maddr);
102*89ac6aa7SJohn Johansen 
103*89ac6aa7SJohn Johansen 	maddr->addrtype = addrtype;
104*89ac6aa7SJohn Johansen 	if (!addr || addrlen < offsetofend(struct sockaddr, sa_family)) {
105*89ac6aa7SJohn Johansen 		maddr->addrp = NULL;
106*89ac6aa7SJohn Johansen 		maddr->port = 0;
107*89ac6aa7SJohn Johansen 		maddr->len = 0;
108*89ac6aa7SJohn Johansen 		return 0;
109*89ac6aa7SJohn Johansen 	}
110*89ac6aa7SJohn Johansen 
111*89ac6aa7SJohn Johansen 	/*
112*89ac6aa7SJohn Johansen 	 * its possibly to have sk->sk_family == PF_INET6 and
113*89ac6aa7SJohn Johansen 	 * addr->sa_family == AF_INET. sk_family is used for socket
114*89ac6aa7SJohn Johansen 	 * mediation, sa_family for when we have address ...
115*89ac6aa7SJohn Johansen 	 */
116*89ac6aa7SJohn Johansen 	switch (addr->sa_family) {
117*89ac6aa7SJohn Johansen 	case AF_INET:
118*89ac6aa7SJohn Johansen 		addr4 = (struct sockaddr_in *)addr;
119*89ac6aa7SJohn Johansen 		if (addrlen < sizeof(struct sockaddr_in))
120*89ac6aa7SJohn Johansen 			return -EINVAL;
121*89ac6aa7SJohn Johansen 		maddr->port = addr4->sin_port;
122*89ac6aa7SJohn Johansen 		maddr->addrp = (char *)&addr4->sin_addr.s_addr;
123*89ac6aa7SJohn Johansen 		maddr->len = 4;
124*89ac6aa7SJohn Johansen 		break;
125*89ac6aa7SJohn Johansen 	case AF_INET6:
126*89ac6aa7SJohn Johansen 		addr6 = (struct sockaddr_in6 *)addr;
127*89ac6aa7SJohn Johansen 		if (addrlen < SIN6_LEN_RFC2133)
128*89ac6aa7SJohn Johansen 			return -EINVAL;
129*89ac6aa7SJohn Johansen 		maddr->port = addr6->sin6_port;
130*89ac6aa7SJohn Johansen 		maddr->addrp = (char *)&addr6->sin6_addr.s6_addr;
131*89ac6aa7SJohn Johansen 		maddr->len = 16;
132*89ac6aa7SJohn Johansen 		break;
133*89ac6aa7SJohn Johansen 	default:
134*89ac6aa7SJohn Johansen 		return -EAFNOSUPPORT;
135*89ac6aa7SJohn Johansen 	}
136*89ac6aa7SJohn Johansen 	/* per ip spec, && sk->sk_type == SOCK_RAW*/
137*89ac6aa7SJohn Johansen 	if (raw_port && addrtype != ADDR_REMOTE)
138*89ac6aa7SJohn Johansen 		maddr->port = htons(raw_port);
139*89ac6aa7SJohn Johansen 	if (ad)
140*89ac6aa7SJohn Johansen 		set_ad_addr(ad, addr->sa_family, addrtype != ADDR_REMOTE, maddr);
141*89ac6aa7SJohn Johansen 
142*89ac6aa7SJohn Johansen 	return 0;
143*89ac6aa7SJohn Johansen }
144*89ac6aa7SJohn Johansen 
145*89ac6aa7SJohn Johansen /* -ENOTCONN if not connected */
map_sock_addr(struct socket * sock,enum addr_type addrtype,struct stored_match_addr * maddr,struct apparmor_audit_data * ad)146*89ac6aa7SJohn Johansen static int map_sock_addr(struct socket *sock, enum addr_type addrtype,
147*89ac6aa7SJohn Johansen 			 struct stored_match_addr *maddr,
148*89ac6aa7SJohn Johansen 			 struct apparmor_audit_data *ad)
149*89ac6aa7SJohn Johansen {
150*89ac6aa7SJohn Johansen 	/* do we need early bailout for !family ... */
151*89ac6aa7SJohn Johansen 	maddr->addrlen = sock->ops->getname(sock, (struct sockaddr *) &maddr->addr, addrtype != ADDR_REMOTE ? 0 : 1);
152*89ac6aa7SJohn Johansen 	if (maddr->addrlen == -ENOTCONN) {
153*89ac6aa7SJohn Johansen 		maddr->addrlen = 0;
154*89ac6aa7SJohn Johansen 		return map_addr(NULL, 0, 0, addrtype, &maddr->maddr, ad);
155*89ac6aa7SJohn Johansen 	} else if (maddr->addrlen < 0)
156*89ac6aa7SJohn Johansen 		return maddr->addrlen;
157*89ac6aa7SJohn Johansen 	return map_addr(&maddr->addr, maddr->addrlen, 0, addrtype,
158*89ac6aa7SJohn Johansen 			&maddr->maddr, ad);
159*89ac6aa7SJohn Johansen }
160*89ac6aa7SJohn Johansen 
161*89ac6aa7SJohn Johansen /* TODO: combine with connect map addr */
162*89ac6aa7SJohn Johansen /* TODO: raw_port */
bind_map_addr(const struct sock * sk,struct sockaddr * addr,int addrlen,struct match_addr * maddr,struct apparmor_audit_data * ad)163*89ac6aa7SJohn Johansen static int bind_map_addr(const struct sock *sk, struct sockaddr *addr,
164*89ac6aa7SJohn Johansen 			 int addrlen,
165*89ac6aa7SJohn Johansen 			 struct match_addr *maddr,
166*89ac6aa7SJohn Johansen 			 struct apparmor_audit_data *ad)
167*89ac6aa7SJohn Johansen {
168*89ac6aa7SJohn Johansen 	struct sockaddr_in *addr4 = NULL;
169*89ac6aa7SJohn Johansen 	struct sockaddr_in6 *addr6 = NULL;
170*89ac6aa7SJohn Johansen 	u16 family;
171*89ac6aa7SJohn Johansen 
172*89ac6aa7SJohn Johansen 	AA_BUG(!sk);
173*89ac6aa7SJohn Johansen 	AA_BUG(!addr);
174*89ac6aa7SJohn Johansen 	AA_BUG(!maddr);
175*89ac6aa7SJohn Johansen 
176*89ac6aa7SJohn Johansen 	if (addrlen < offsetofend(struct sockaddr, sa_family))
177*89ac6aa7SJohn Johansen 		return -EINVAL;
178*89ac6aa7SJohn Johansen 
179*89ac6aa7SJohn Johansen 	maddr->addrtype = ADDR_LOCAL;
180*89ac6aa7SJohn Johansen 	/*
181*89ac6aa7SJohn Johansen 	 * its possibly to have sk->sk_family == PF_INET6 and
182*89ac6aa7SJohn Johansen 	 * addr->sa_family == AF_INET. sk_family is used for socket
183*89ac6aa7SJohn Johansen 	 * mediation, sa_family for when we have address ...
184*89ac6aa7SJohn Johansen 	 */
185*89ac6aa7SJohn Johansen 	family = addr->sa_family;
186*89ac6aa7SJohn Johansen 	switch (addr->sa_family) {
187*89ac6aa7SJohn Johansen 	case AF_UNSPEC:
188*89ac6aa7SJohn Johansen 		if (sk->sk_family == PF_INET6) {
189*89ac6aa7SJohn Johansen 			/* Length check from inet6_bind_sk() */
190*89ac6aa7SJohn Johansen 			if (addrlen < SIN6_LEN_RFC2133)
191*89ac6aa7SJohn Johansen 				return -EINVAL;
192*89ac6aa7SJohn Johansen 			/* Family check from __inet6_bind() */
193*89ac6aa7SJohn Johansen 			return -EAFNOSUPPORT;
194*89ac6aa7SJohn Johansen 		}
195*89ac6aa7SJohn Johansen 		/* see __inet_bind(), we only want to allow
196*89ac6aa7SJohn Johansen 		 * AF_UNSPEC if the address is INADDR_ANY
197*89ac6aa7SJohn Johansen 		 */
198*89ac6aa7SJohn Johansen 		addr4 = (struct sockaddr_in *)addr;
199*89ac6aa7SJohn Johansen 		if (addr4->sin_addr.s_addr != htonl(INADDR_ANY))
200*89ac6aa7SJohn Johansen 			return -EAFNOSUPPORT;
201*89ac6aa7SJohn Johansen 		family = AF_INET;
202*89ac6aa7SJohn Johansen 		fallthrough;
203*89ac6aa7SJohn Johansen 	case AF_INET:
204*89ac6aa7SJohn Johansen 		addr4 = (struct sockaddr_in *)addr;
205*89ac6aa7SJohn Johansen 		if (addrlen < sizeof(struct sockaddr_in))
206*89ac6aa7SJohn Johansen 			return -EINVAL;
207*89ac6aa7SJohn Johansen 		maddr->port = addr4->sin_port;
208*89ac6aa7SJohn Johansen 		maddr->addrp = (char *)&addr4->sin_addr.s_addr;
209*89ac6aa7SJohn Johansen 		maddr->len = 4;
210*89ac6aa7SJohn Johansen 		break;
211*89ac6aa7SJohn Johansen 	case AF_INET6:
212*89ac6aa7SJohn Johansen 		addr6 = (struct sockaddr_in6 *)addr;
213*89ac6aa7SJohn Johansen 		if (addrlen < SIN6_LEN_RFC2133)
214*89ac6aa7SJohn Johansen 			return -EINVAL;
215*89ac6aa7SJohn Johansen 		maddr->port = addr6->sin6_port;
216*89ac6aa7SJohn Johansen 		maddr->addrp = (char *)&addr6->sin6_addr.s6_addr;
217*89ac6aa7SJohn Johansen 		maddr->len = 16;
218*89ac6aa7SJohn Johansen 		break;
219*89ac6aa7SJohn Johansen 	default:
220*89ac6aa7SJohn Johansen 		return -EAFNOSUPPORT;
221*89ac6aa7SJohn Johansen 	}
222*89ac6aa7SJohn Johansen 
223*89ac6aa7SJohn Johansen 	if (ad)
224*89ac6aa7SJohn Johansen 		set_ad_addr(ad, family, true, maddr);
225*89ac6aa7SJohn Johansen 
226*89ac6aa7SJohn Johansen 	return 0;
227*89ac6aa7SJohn Johansen }
228*89ac6aa7SJohn Johansen 
229*89ac6aa7SJohn Johansen 
profile_sk_perm(struct aa_profile * profile,u32 request,const struct sock * sk,struct match_addr * maddr,struct apparmor_audit_data * ad)230*89ac6aa7SJohn Johansen static inline int profile_sk_perm(struct aa_profile *profile, u32 request,
231*89ac6aa7SJohn Johansen 				  const struct sock *sk,
232*89ac6aa7SJohn Johansen 				  struct match_addr *maddr,
233*89ac6aa7SJohn Johansen 				  struct apparmor_audit_data *ad)
234*89ac6aa7SJohn Johansen {
235*89ac6aa7SJohn Johansen 	AA_BUG(!profile);
236*89ac6aa7SJohn Johansen 	AA_BUG(!sk);
237*89ac6aa7SJohn Johansen 
238*89ac6aa7SJohn Johansen 	return aa_profile_af_sk_perm(profile, ad, request, sk);
239*89ac6aa7SJohn Johansen }
240*89ac6aa7SJohn Johansen 
241*89ac6aa7SJohn Johansen /* no kernel_t bailout */
profile_create_perm(struct aa_profile * profile,int family,int type,int protocol,struct apparmor_audit_data * ad)242*89ac6aa7SJohn Johansen static int profile_create_perm(struct aa_profile *profile, int family,
243*89ac6aa7SJohn Johansen 			       int type, int protocol,
244*89ac6aa7SJohn Johansen 			       struct apparmor_audit_data *ad)
245*89ac6aa7SJohn Johansen {
246*89ac6aa7SJohn Johansen 	AA_BUG(!profile);
247*89ac6aa7SJohn Johansen 
248*89ac6aa7SJohn Johansen 	return aa_profile_af_perm(profile, ad, AA_MAY_CREATE, family, type,
249*89ac6aa7SJohn Johansen 				  protocol);
250*89ac6aa7SJohn Johansen }
251*89ac6aa7SJohn Johansen 
252*89ac6aa7SJohn Johansen 
253*89ac6aa7SJohn Johansen /* sendmsg/rcvmsg/connect */
profile_remote_perm(struct aa_profile * profile,const struct sock * sk,u32 request,struct match_addr * raddr,struct match_addr * laddr,struct apparmor_audit_data * ad)254*89ac6aa7SJohn Johansen static int profile_remote_perm(struct aa_profile *profile,
255*89ac6aa7SJohn Johansen 			       const struct sock *sk,
256*89ac6aa7SJohn Johansen 			       u32 request, struct match_addr *raddr,
257*89ac6aa7SJohn Johansen 			       struct match_addr *laddr,
258*89ac6aa7SJohn Johansen 			       struct apparmor_audit_data *ad)
259*89ac6aa7SJohn Johansen {
260*89ac6aa7SJohn Johansen 	AA_BUG(!profile);
261*89ac6aa7SJohn Johansen 	AA_BUG(!sk);
262*89ac6aa7SJohn Johansen 	AA_BUG(!raddr);
263*89ac6aa7SJohn Johansen 	AA_BUG(!laddr);
264*89ac6aa7SJohn Johansen 	AA_BUG(sk->sk_family != PF_INET && sk->sk_family != PF_INET6,
265*89ac6aa7SJohn Johansen 	       "family=%d", sk->sk_family);
266*89ac6aa7SJohn Johansen 
267*89ac6aa7SJohn Johansen 	return aa_profile_af_sk_perm(profile, ad, request, sk);
268*89ac6aa7SJohn Johansen }
269*89ac6aa7SJohn Johansen 
profile_bind_perm(struct aa_profile * profile,const struct sock * sk,struct match_addr * maddr,struct apparmor_audit_data * ad)270*89ac6aa7SJohn Johansen static int profile_bind_perm(struct aa_profile *profile,
271*89ac6aa7SJohn Johansen 			     const struct sock *sk,
272*89ac6aa7SJohn Johansen 			     struct match_addr *maddr,
273*89ac6aa7SJohn Johansen 			     struct apparmor_audit_data *ad)
274*89ac6aa7SJohn Johansen {
275*89ac6aa7SJohn Johansen 	return aa_profile_af_sk_perm(profile, ad, AA_MAY_BIND, sk);
276*89ac6aa7SJohn Johansen 
277*89ac6aa7SJohn Johansen }
278*89ac6aa7SJohn Johansen 
profile_listen_perm(struct aa_profile * profile,const struct sock * sk,struct match_addr * maddr,int backlog,struct apparmor_audit_data * ad)279*89ac6aa7SJohn Johansen static int profile_listen_perm(struct aa_profile *profile,
280*89ac6aa7SJohn Johansen 			       const struct sock *sk,
281*89ac6aa7SJohn Johansen 			       struct match_addr *maddr, int backlog,
282*89ac6aa7SJohn Johansen 			       struct apparmor_audit_data *ad)
283*89ac6aa7SJohn Johansen {
284*89ac6aa7SJohn Johansen 	AA_BUG(!profile);
285*89ac6aa7SJohn Johansen 	AA_BUG(!sk);
286*89ac6aa7SJohn Johansen 	AA_BUG(!maddr);
287*89ac6aa7SJohn Johansen 	AA_BUG(sk->sk_family != PF_INET && sk->sk_family != PF_INET6,
288*89ac6aa7SJohn Johansen 	       "family=%d", sk->sk_family);
289*89ac6aa7SJohn Johansen 
290*89ac6aa7SJohn Johansen 	return aa_profile_af_sk_perm(profile, ad, AA_MAY_LISTEN, sk);
291*89ac6aa7SJohn Johansen }
292*89ac6aa7SJohn Johansen 
profile_accept_perm(struct aa_profile * profile,const struct sock * sk,struct match_addr * maddr,const struct sock * newsk,struct apparmor_audit_data * ad)293*89ac6aa7SJohn Johansen static inline int profile_accept_perm(struct aa_profile *profile,
294*89ac6aa7SJohn Johansen 				      const struct sock *sk,
295*89ac6aa7SJohn Johansen 				      struct match_addr *maddr,
296*89ac6aa7SJohn Johansen 				      const struct sock *newsk,
297*89ac6aa7SJohn Johansen 				      struct apparmor_audit_data *ad)
298*89ac6aa7SJohn Johansen {
299*89ac6aa7SJohn Johansen 	AA_BUG(!profile);
300*89ac6aa7SJohn Johansen 	AA_BUG(!sk);
301*89ac6aa7SJohn Johansen 	/* AA_BUG(!newsk);  newsk can be null here, since not using atm ... */
302*89ac6aa7SJohn Johansen 	AA_BUG(!maddr);
303*89ac6aa7SJohn Johansen 	AA_BUG(sk->sk_family != PF_INET && sk->sk_family != PF_INET6,
304*89ac6aa7SJohn Johansen 	       "family=%d", sk->sk_family);
305*89ac6aa7SJohn Johansen 
306*89ac6aa7SJohn Johansen 	return aa_profile_af_sk_perm(profile, ad, AA_MAY_ACCEPT, sk);
307*89ac6aa7SJohn Johansen }
308*89ac6aa7SJohn Johansen 
309*89ac6aa7SJohn Johansen /* getopt/setopt */
profile_opt_perm(struct aa_profile * profile,u32 request,const struct sock * sk,struct match_addr * maddr,int level,int optname,struct apparmor_audit_data * ad)310*89ac6aa7SJohn Johansen static int profile_opt_perm(struct aa_profile *profile, u32 request,
311*89ac6aa7SJohn Johansen 			    const struct sock *sk, struct match_addr *maddr,
312*89ac6aa7SJohn Johansen 			    int level, int optname,
313*89ac6aa7SJohn Johansen 			    struct apparmor_audit_data *ad)
314*89ac6aa7SJohn Johansen {
315*89ac6aa7SJohn Johansen 	AA_BUG(!profile);
316*89ac6aa7SJohn Johansen 	AA_BUG(!sk);
317*89ac6aa7SJohn Johansen 	AA_BUG(!maddr);
318*89ac6aa7SJohn Johansen 	AA_BUG(sk->sk_family != PF_INET && sk->sk_family != PF_INET6,
319*89ac6aa7SJohn Johansen 	       "family=%d", sk->sk_family);
320*89ac6aa7SJohn Johansen 
321*89ac6aa7SJohn Johansen 	return aa_profile_af_sk_perm(profile, ad, request, sk);
322*89ac6aa7SJohn Johansen }
323*89ac6aa7SJohn Johansen 
324*89ac6aa7SJohn Johansen /* ---------------------------------------------------------------------- */
325*89ac6aa7SJohn Johansen 
326*89ac6aa7SJohn Johansen // TODO: cleanup init to use recursion, so we can have N init fns, in 1 macro
327*89ac6aa7SJohn Johansen // TODO: lift DEFINE_AUDIT out of macro into init fn???
328*89ac6aa7SJohn Johansen 
329*89ac6aa7SJohn Johansen /* no kernel_t bailout */
330*89ac6aa7SJohn Johansen #define label_sk_has_perm2(CRED, LABEL, SOCKSK, OP, REQUEST, PROFILE, AAD, XXXX, YYYY, CALLBACKFN) \
331*89ac6aa7SJohn Johansen ({								\
332*89ac6aa7SJohn Johansen 	int __EERROR = 0;					\
333*89ac6aa7SJohn Johansen 	if (label_mediates(LABEL, AA_CLASS_NET)) {		\
334*89ac6aa7SJohn Johansen 		struct aa_profile *PROFILE;			\
335*89ac6aa7SJohn Johansen 		DEFINE_AUDIT_SK(AAD, OP, CRED, SOCKSK);		\
336*89ac6aa7SJohn Johansen 		(AAD).subj_cred = (CRED);			\
337*89ac6aa7SJohn Johansen 		(AAD).request = (REQUEST);			\
338*89ac6aa7SJohn Johansen 		__EERROR = (XXXX);				\
339*89ac6aa7SJohn Johansen 		if (__EERROR == 0) {				\
340*89ac6aa7SJohn Johansen 			__EERROR = (YYYY);			\
341*89ac6aa7SJohn Johansen 			if (__EERROR == 0) {			\
342*89ac6aa7SJohn Johansen 				__EERROR = fn_for_each(LABEL, PROFILE,	\
343*89ac6aa7SJohn Johansen 						       (CALLBACKFN));	\
344*89ac6aa7SJohn Johansen 			}						\
345*89ac6aa7SJohn Johansen 		}							\
346*89ac6aa7SJohn Johansen 	}							\
347*89ac6aa7SJohn Johansen 	__EERROR;						\
348*89ac6aa7SJohn Johansen })
349*89ac6aa7SJohn Johansen 
350*89ac6aa7SJohn Johansen /* no kernel_t bailout */
351*89ac6aa7SJohn Johansen #define label_sk_has_perm(CRED, LABEL, SOCKSK, OP, REQUEST, PROFILE, AAD, CALLBACKFN) \
352*89ac6aa7SJohn Johansen 	label_sk_has_perm2(CRED, LABEL, SOCKSK, OP, REQUEST, PROFILE, AAD, \
353*89ac6aa7SJohn Johansen 			   0, 0, CALLBACKFN)
354*89ac6aa7SJohn Johansen 
355*89ac6aa7SJohn Johansen /* no kernel_t bailout */
356*89ac6aa7SJohn Johansen #define label_sk_has_perm1(CRED, LABEL, SOCKSK, OP, REQUEST, PROFILE, AAD, XXXX, CALLBACKFN) \
357*89ac6aa7SJohn Johansen 	label_sk_has_perm2(CRED, LABEL, SOCKSK, OP, REQUEST, PROFILE, AAD, \
358*89ac6aa7SJohn Johansen 			   XXXX, 0, CALLBACKFN)
359*89ac6aa7SJohn Johansen 
360*89ac6aa7SJohn Johansen 
361*89ac6aa7SJohn Johansen /* Early bailout for kernel_t - 2 init args before callback */
362*89ac6aa7SJohn Johansen #define sk_has_perm2(SOCKSK, OP, REQUEST, PROFILE, AAD, XXXXY, YYYYX, CALLBACKFN) \
363*89ac6aa7SJohn Johansen ({									\
364*89ac6aa7SJohn Johansen 	struct aa_label *__label;					\
365*89ac6aa7SJohn Johansen 	struct aa_sk_ctx *__ctx = aa_sock(SOCKSK);			\
366*89ac6aa7SJohn Johansen 	int __ERROR = 0;						\
367*89ac6aa7SJohn Johansen 	bool __needput;						\
368*89ac6aa7SJohn Johansen 	if (rcu_access_pointer(__ctx->label) != kernel_t) {		\
369*89ac6aa7SJohn Johansen 									\
370*89ac6aa7SJohn Johansen 		__label = begin_current_label_crit_section(&__needput);	\
371*89ac6aa7SJohn Johansen                 __ERROR = label_sk_has_perm2(current_cred(), __label, SOCKSK, OP, REQUEST, PROFILE, AAD, XXXXY, YYYYX, CALLBACKFN); \
372*89ac6aa7SJohn Johansen 		end_current_label_crit_section(__label, __needput);	\
373*89ac6aa7SJohn Johansen 	}								\
374*89ac6aa7SJohn Johansen 	__ERROR;							\
375*89ac6aa7SJohn Johansen })
376*89ac6aa7SJohn Johansen 
377*89ac6aa7SJohn Johansen /* Early bailout for kernel_t - no init args before callback */
378*89ac6aa7SJohn Johansen #define sk_has_perm(SOCKSK, OP, REQUEST, PROFILE, AAD, CALLBACKFN)	\
379*89ac6aa7SJohn Johansen 	sk_has_perm2(SOCKSK, OP, REQUEST, PROFILE, AAD, 0, 0, CALLBACKFN)
380*89ac6aa7SJohn Johansen 
381*89ac6aa7SJohn Johansen 
382*89ac6aa7SJohn Johansen /* Early bailout for kernel_t - 1 init arg before callback */
383*89ac6aa7SJohn Johansen #define sk_has_perm1(SOCKSK, OP, REQUEST, PROFILE, AAD, XXXXY, CALLBACKFN) \
384*89ac6aa7SJohn Johansen 	sk_has_perm2(SOCKSK, OP, REQUEST, PROFILE, AAD, XXXXY, 0, CALLBACKFN)
385*89ac6aa7SJohn Johansen 
386*89ac6aa7SJohn Johansen 
387*89ac6aa7SJohn Johansen 
3884f0cafcbSJohn Johansen /* no kernel_t early bailout */
3894f0cafcbSJohn Johansen /* NOTE: already lifted label_mediates into lsm.c */
aa_inet_create_perm(struct aa_label * label,int family,int type,int protocol)3904f0cafcbSJohn Johansen int aa_inet_create_perm(struct aa_label *label, int family, int type,
3914f0cafcbSJohn Johansen 			int protocol)
3924f0cafcbSJohn Johansen {
393*89ac6aa7SJohn Johansen 	struct aa_profile *profile;
394*89ac6aa7SJohn Johansen 	int error = 0;
395*89ac6aa7SJohn Johansen 	DEFINE_AUDIT_NET(ad, OP_CREATE, current_cred(), NULL, family, type,
3964f0cafcbSJohn Johansen 			 protocol);
397*89ac6aa7SJohn Johansen 
398*89ac6aa7SJohn Johansen 	ad.subj_cred = current_cred();
399*89ac6aa7SJohn Johansen 	set_ad_create(&ad, family, type, protocol);
400*89ac6aa7SJohn Johansen 	error = fn_for_each(label, profile,
401*89ac6aa7SJohn Johansen 			    profile_create_perm(profile, family, type,
402*89ac6aa7SJohn Johansen 						protocol, &ad));
403*89ac6aa7SJohn Johansen 
404*89ac6aa7SJohn Johansen 	return error;
4054f0cafcbSJohn Johansen }
4064f0cafcbSJohn Johansen 
aa_inet_bind_perm(struct socket * sock,struct sockaddr * addr,int addrlen)4074f0cafcbSJohn Johansen int aa_inet_bind_perm(struct socket *sock, struct sockaddr *addr,
4084f0cafcbSJohn Johansen 		      int addrlen)
4094f0cafcbSJohn Johansen {
410*89ac6aa7SJohn Johansen 	struct match_addr maddr;
411*89ac6aa7SJohn Johansen 
412*89ac6aa7SJohn Johansen 	return sk_has_perm1(sock->sk, OP_BIND, AA_MAY_BIND, profile, ad,
413*89ac6aa7SJohn Johansen 			    bind_map_addr(sock->sk, addr, addrlen, &maddr,
414*89ac6aa7SJohn Johansen 					  &ad),
415*89ac6aa7SJohn Johansen 			    profile_bind_perm(profile, sock->sk, &maddr, &ad));
4164f0cafcbSJohn Johansen }
4174f0cafcbSJohn Johansen 
aa_inet_connect_perm(struct socket * sock,struct sockaddr * addr,int addrlen)4184f0cafcbSJohn Johansen int aa_inet_connect_perm(struct socket *sock, struct sockaddr *addr,
4194f0cafcbSJohn Johansen 			 int addrlen)
4204f0cafcbSJohn Johansen {
421*89ac6aa7SJohn Johansen 	struct stored_match_addr laddr;
422*89ac6aa7SJohn Johansen 	struct match_addr raddr;
423*89ac6aa7SJohn Johansen 
424*89ac6aa7SJohn Johansen 	/* disconnect socket */
425*89ac6aa7SJohn Johansen 	if (addrlen < offsetofend(struct sockaddr, sa_family))
426*89ac6aa7SJohn Johansen 		return -EINVAL;
427*89ac6aa7SJohn Johansen 	if (addr->sa_family == AF_UNSPEC)
428*89ac6aa7SJohn Johansen 		return 0;
429*89ac6aa7SJohn Johansen 
430*89ac6aa7SJohn Johansen 	/* do we need early bailout for !family ... */
431*89ac6aa7SJohn Johansen 	return sk_has_perm2(sock->sk, OP_CONNECT, AA_MAY_CONNECT, profile, ad,
432*89ac6aa7SJohn Johansen 			    map_sock_addr(sock, ADDR_LOCAL, &laddr, &ad),
433*89ac6aa7SJohn Johansen 			    map_addr(addr, addrlen, 0, ADDR_REMOTE, &raddr,
434*89ac6aa7SJohn Johansen 				     &ad),
435*89ac6aa7SJohn Johansen 			    profile_remote_perm(profile, sock->sk,
436*89ac6aa7SJohn Johansen 						AA_MAY_CONNECT, &raddr,
437*89ac6aa7SJohn Johansen 						&laddr.maddr, &ad));
4384f0cafcbSJohn Johansen }
4394f0cafcbSJohn Johansen 
aa_inet_listen_perm(struct socket * sock,int backlog)4404f0cafcbSJohn Johansen int aa_inet_listen_perm(struct socket *sock, int backlog)
4414f0cafcbSJohn Johansen {
442*89ac6aa7SJohn Johansen 	struct stored_match_addr maddr;
443*89ac6aa7SJohn Johansen 
444*89ac6aa7SJohn Johansen 	/* do we need early bailout for !family ... */
445*89ac6aa7SJohn Johansen 	return sk_has_perm1(sock->sk, OP_LISTEN, AA_MAY_LISTEN, profile, ad,
446*89ac6aa7SJohn Johansen 			    map_sock_addr(sock, ADDR_LOCAL, &maddr, &ad),
447*89ac6aa7SJohn Johansen 			    profile_listen_perm(profile, sock->sk, &maddr.maddr,
448*89ac6aa7SJohn Johansen 						backlog, &ad));
4494f0cafcbSJohn Johansen }
4504f0cafcbSJohn Johansen 
4514f0cafcbSJohn Johansen /* ability of sock to connect, not peer address binding */
aa_inet_accept_perm(struct socket * sock,struct socket * newsock)4524f0cafcbSJohn Johansen int aa_inet_accept_perm(struct socket *sock, struct socket *newsock)
4534f0cafcbSJohn Johansen {
454*89ac6aa7SJohn Johansen 	struct stored_match_addr maddr;
455*89ac6aa7SJohn Johansen 	int error;
456*89ac6aa7SJohn Johansen 
457*89ac6aa7SJohn Johansen 	error = sk_has_perm1(sock->sk, OP_ACCEPT, AA_MAY_ACCEPT, profile, ad,
458*89ac6aa7SJohn Johansen 			     map_sock_addr(sock, ADDR_LOCAL, &maddr, &ad),
459*89ac6aa7SJohn Johansen 			     profile_accept_perm(profile, sock->sk,
460*89ac6aa7SJohn Johansen 						 &maddr.maddr,
461*89ac6aa7SJohn Johansen 						 newsock->sk, &ad));
462*89ac6aa7SJohn Johansen 
463*89ac6aa7SJohn Johansen 	/* selinux updates inode - need to investigate this more */
464*89ac6aa7SJohn Johansen 	return error;
4654f0cafcbSJohn Johansen }
4664f0cafcbSJohn Johansen 
4674f0cafcbSJohn Johansen /* sendmsg, recvmsg. */
aa_inet_msg_perm(const char * op,u32 request,struct socket * sock,struct msghdr * msg,int size)4684f0cafcbSJohn Johansen int aa_inet_msg_perm(const char *op, u32 request, struct socket *sock,
4694f0cafcbSJohn Johansen 		     struct msghdr *msg, int size)
4704f0cafcbSJohn Johansen {
471*89ac6aa7SJohn Johansen 	struct stored_match_addr laddr;
472*89ac6aa7SJohn Johansen 	struct match_addr raddr;
473*89ac6aa7SJohn Johansen 
474*89ac6aa7SJohn Johansen 	/* do we need early bailout for !family ... */
475*89ac6aa7SJohn Johansen 	return sk_has_perm2(sock->sk, op, request, profile, ad,
476*89ac6aa7SJohn Johansen 			    map_sock_addr(sock, ADDR_LOCAL, &laddr, &ad),
477*89ac6aa7SJohn Johansen 			    map_addr(msg->msg_name, msg->msg_namelen, 0,
478*89ac6aa7SJohn Johansen 				     ADDR_REMOTE, &raddr, &ad),
479*89ac6aa7SJohn Johansen 			    profile_remote_perm(profile, sock->sk, request,
480*89ac6aa7SJohn Johansen 						&raddr, &laddr.maddr, &ad));
4814f0cafcbSJohn Johansen }
4824f0cafcbSJohn Johansen 
4834f0cafcbSJohn Johansen /* getopt, setopt */
aa_inet_opt_perm(const char * op,u32 request,struct socket * sock,int level,int optname)4844f0cafcbSJohn Johansen int aa_inet_opt_perm(const char *op, u32 request, struct socket *sock,
4854f0cafcbSJohn Johansen 		     int level, int optname)
4864f0cafcbSJohn Johansen {
487*89ac6aa7SJohn Johansen 	struct stored_match_addr maddr;
488*89ac6aa7SJohn Johansen 
489*89ac6aa7SJohn Johansen 	return sk_has_perm1(sock->sk, op, request, profile, ad,
490*89ac6aa7SJohn Johansen 			    map_sock_addr(sock, ADDR_LOCAL, &maddr, &ad),
491*89ac6aa7SJohn Johansen 			    profile_opt_perm(profile, request, sock->sk,
492*89ac6aa7SJohn Johansen 					    &maddr.maddr, level, optname, &ad));
4934f0cafcbSJohn Johansen }
4944f0cafcbSJohn Johansen 
inet_label_sock_perm(const struct cred * cred,struct aa_label * label,const char * op,u32 request,struct socket * sock)495*89ac6aa7SJohn Johansen static int inet_label_sock_perm(const struct cred *cred, struct aa_label *label,
496*89ac6aa7SJohn Johansen 				const char *op, u32 request,
497*89ac6aa7SJohn Johansen 				struct socket *sock)
498*89ac6aa7SJohn Johansen {
499*89ac6aa7SJohn Johansen 	struct stored_match_addr maddr;
500*89ac6aa7SJohn Johansen 
501*89ac6aa7SJohn Johansen 	return label_sk_has_perm1(cred, label, sock->sk, op, request, profile,
502*89ac6aa7SJohn Johansen 				  ad,
503*89ac6aa7SJohn Johansen 			map_sock_addr(sock, ADDR_LOCAL, &maddr, &ad),
504*89ac6aa7SJohn Johansen 			profile_sk_perm(profile, request, sock->sk,
505*89ac6aa7SJohn Johansen 					&maddr.maddr, &ad));
506*89ac6aa7SJohn Johansen }
507*89ac6aa7SJohn Johansen 
508*89ac6aa7SJohn Johansen /* revalidation, get/set attr/getsockname/peername */
aa_inet_sock_perm(const char * op,u32 request,struct socket * sock)5094f0cafcbSJohn Johansen int aa_inet_sock_perm(const char *op, u32 request, struct socket *sock)
5104f0cafcbSJohn Johansen {
511*89ac6aa7SJohn Johansen 	struct aa_sk_ctx *ctx = aa_sock(sock->sk);
512*89ac6aa7SJohn Johansen 	struct aa_label *label;
513*89ac6aa7SJohn Johansen 	bool needput;
514*89ac6aa7SJohn Johansen 	int error;
515*89ac6aa7SJohn Johansen 
516*89ac6aa7SJohn Johansen 	if (rcu_access_pointer(ctx->label) == kernel_t)
517*89ac6aa7SJohn Johansen 		return 0;
518*89ac6aa7SJohn Johansen 
519*89ac6aa7SJohn Johansen 	label = begin_current_label_crit_section(&needput);
520*89ac6aa7SJohn Johansen 	error = inet_label_sock_perm(current_cred(), label, op, request, sock);
521*89ac6aa7SJohn Johansen 	end_current_label_crit_section(label, needput);
522*89ac6aa7SJohn Johansen 
523*89ac6aa7SJohn Johansen 	return error;
5244f0cafcbSJohn Johansen }
5254f0cafcbSJohn Johansen 
aa_inet_file_perm(const struct cred * subj_cred,struct aa_label * label,const char * op,u32 request,struct socket * sock)5264f0cafcbSJohn Johansen int aa_inet_file_perm(const struct cred *subj_cred, struct aa_label *label,
5274f0cafcbSJohn Johansen 		      const char *op, u32 request, struct socket *sock)
5284f0cafcbSJohn Johansen {
529*89ac6aa7SJohn Johansen 	u32 sk_req = request & ~NET_PEER_MASK;
530*89ac6aa7SJohn Johansen 	struct stored_match_addr laddr;
531*89ac6aa7SJohn Johansen 	const struct sock *sk = sock->sk;
532*89ac6aa7SJohn Johansen 	int error = 0;
533*89ac6aa7SJohn Johansen 
534*89ac6aa7SJohn Johansen 	AA_BUG(!label);
535*89ac6aa7SJohn Johansen 	AA_BUG(!sock);
536*89ac6aa7SJohn Johansen 	AA_BUG(!sock->sk);
537*89ac6aa7SJohn Johansen 	AA_BUG(sk->sk_family != PF_INET && sk->sk_family != PF_INET6,
538*89ac6aa7SJohn Johansen 	       "family=%d", sk->sk_family);
539*89ac6aa7SJohn Johansen 
540*89ac6aa7SJohn Johansen 	/* access to the local sock */
541*89ac6aa7SJohn Johansen 	error = label_sk_has_perm1(subj_cred, label, sock->sk, op, request,
542*89ac6aa7SJohn Johansen 				   profile, ad,
543*89ac6aa7SJohn Johansen 			map_sock_addr(sock, ADDR_LOCAL, &laddr, &ad),
544*89ac6aa7SJohn Johansen 			profile_sk_perm(profile, sk_req, sock->sk, &laddr.maddr,
545*89ac6aa7SJohn Johansen 					&ad));
546*89ac6aa7SJohn Johansen 
547*89ac6aa7SJohn Johansen 	if (!error) {
548*89ac6aa7SJohn Johansen 		struct stored_match_addr raddr;
549*89ac6aa7SJohn Johansen 
550*89ac6aa7SJohn Johansen 		/* TODO: have ad here: instead of in CB so we do have to redo */
551*89ac6aa7SJohn Johansen 		error = map_sock_addr(sock, ADDR_REMOTE, &raddr, NULL);
552*89ac6aa7SJohn Johansen 		if (!error && raddr.maddr.addrp) {
553*89ac6aa7SJohn Johansen 			error = label_sk_has_perm1(subj_cred, label, sock->sk,
554*89ac6aa7SJohn Johansen 						   op, request, profile, ad,
555*89ac6aa7SJohn Johansen 					set_ad_addr(&ad, raddr.addr.sa_family,
556*89ac6aa7SJohn Johansen 						    false, &raddr.maddr),
557*89ac6aa7SJohn Johansen 					profile_remote_perm(profile, sock->sk,
558*89ac6aa7SJohn Johansen 							    request,
559*89ac6aa7SJohn Johansen 							    &raddr.maddr,
560*89ac6aa7SJohn Johansen 							    &laddr.maddr, &ad));
561*89ac6aa7SJohn Johansen 		}
562*89ac6aa7SJohn Johansen 	}
563*89ac6aa7SJohn Johansen 
564*89ac6aa7SJohn Johansen 	return error;
5654f0cafcbSJohn Johansen }
566