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