xref: /openbmc/linux/security/apparmor/net.c (revision f1d9b23cabc61e58509164c3c3132556476491d2)
1b886d83cSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
256974a6fSJohn Johansen /*
356974a6fSJohn Johansen  * AppArmor security module
456974a6fSJohn Johansen  *
556974a6fSJohn Johansen  * This file contains AppArmor network mediation
656974a6fSJohn Johansen  *
756974a6fSJohn Johansen  * Copyright (C) 1998-2008 Novell/SUSE
856974a6fSJohn Johansen  * Copyright 2009-2017 Canonical Ltd.
956974a6fSJohn Johansen  */
1056974a6fSJohn Johansen 
1156974a6fSJohn Johansen #include "include/apparmor.h"
1256974a6fSJohn Johansen #include "include/audit.h"
1356974a6fSJohn Johansen #include "include/cred.h"
1456974a6fSJohn Johansen #include "include/label.h"
1556974a6fSJohn Johansen #include "include/net.h"
1656974a6fSJohn Johansen #include "include/policy.h"
17ab9f2115SMatthew Garrett #include "include/secid.h"
1856974a6fSJohn Johansen 
1956974a6fSJohn Johansen #include "net_names.h"
2056974a6fSJohn Johansen 
2156974a6fSJohn Johansen 
2256974a6fSJohn Johansen struct aa_sfs_entry aa_sfs_entry_network[] = {
2356974a6fSJohn Johansen 	AA_SFS_FILE_STRING("af_mask",	AA_SFS_AF_MASK),
2456974a6fSJohn Johansen 	{ }
2556974a6fSJohn Johansen };
2656974a6fSJohn Johansen 
2756974a6fSJohn Johansen static const char * const net_mask_names[] = {
2856974a6fSJohn Johansen 	"unknown",
2956974a6fSJohn Johansen 	"send",
3056974a6fSJohn Johansen 	"receive",
3156974a6fSJohn Johansen 	"unknown",
3256974a6fSJohn Johansen 
3356974a6fSJohn Johansen 	"create",
3456974a6fSJohn Johansen 	"shutdown",
3556974a6fSJohn Johansen 	"connect",
3656974a6fSJohn Johansen 	"unknown",
3756974a6fSJohn Johansen 
3856974a6fSJohn Johansen 	"setattr",
3956974a6fSJohn Johansen 	"getattr",
4056974a6fSJohn Johansen 	"setcred",
4156974a6fSJohn Johansen 	"getcred",
4256974a6fSJohn Johansen 
4356974a6fSJohn Johansen 	"chmod",
4456974a6fSJohn Johansen 	"chown",
4556974a6fSJohn Johansen 	"chgrp",
4656974a6fSJohn Johansen 	"lock",
4756974a6fSJohn Johansen 
4856974a6fSJohn Johansen 	"mmap",
4956974a6fSJohn Johansen 	"mprot",
5056974a6fSJohn Johansen 	"unknown",
5156974a6fSJohn Johansen 	"unknown",
5256974a6fSJohn Johansen 
5356974a6fSJohn Johansen 	"accept",
5456974a6fSJohn Johansen 	"bind",
5556974a6fSJohn Johansen 	"listen",
5656974a6fSJohn Johansen 	"unknown",
5756974a6fSJohn Johansen 
5856974a6fSJohn Johansen 	"setopt",
5956974a6fSJohn Johansen 	"getopt",
6056974a6fSJohn Johansen 	"unknown",
6156974a6fSJohn Johansen 	"unknown",
6256974a6fSJohn Johansen 
6356974a6fSJohn Johansen 	"unknown",
6456974a6fSJohn Johansen 	"unknown",
6556974a6fSJohn Johansen 	"unknown",
6656974a6fSJohn Johansen 	"unknown",
6756974a6fSJohn Johansen };
6856974a6fSJohn Johansen 
6956974a6fSJohn Johansen 
7056974a6fSJohn Johansen /* audit callback for net specific fields */
7156974a6fSJohn Johansen void audit_net_cb(struct audit_buffer *ab, void *va)
7256974a6fSJohn Johansen {
7356974a6fSJohn Johansen 	struct common_audit_data *sa = va;
7456974a6fSJohn Johansen 
7556974a6fSJohn Johansen 	if (address_family_names[sa->u.net->family])
76*f1d9b23cSRichard Guy Briggs 		audit_log_format(ab, " family=\"%s\"",
77*f1d9b23cSRichard Guy Briggs 				 address_family_names[sa->u.net->family]);
7856974a6fSJohn Johansen 	else
79*f1d9b23cSRichard Guy Briggs 		audit_log_format(ab, " family=\"unknown(%d)\"",
80*f1d9b23cSRichard Guy Briggs 				 sa->u.net->family);
8156974a6fSJohn Johansen 	if (sock_type_names[aad(sa)->net.type])
82*f1d9b23cSRichard Guy Briggs 		audit_log_format(ab, " sock_type=\"%s\"",
83*f1d9b23cSRichard Guy Briggs 				 sock_type_names[aad(sa)->net.type]);
8456974a6fSJohn Johansen 	else
85*f1d9b23cSRichard Guy Briggs 		audit_log_format(ab, " sock_type=\"unknown(%d)\"",
86*f1d9b23cSRichard Guy Briggs 				 aad(sa)->net.type);
8756974a6fSJohn Johansen 	audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
8856974a6fSJohn Johansen 
8956974a6fSJohn Johansen 	if (aad(sa)->request & NET_PERMS_MASK) {
9056974a6fSJohn Johansen 		audit_log_format(ab, " requested_mask=");
9156974a6fSJohn Johansen 		aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0,
9256974a6fSJohn Johansen 				   net_mask_names, NET_PERMS_MASK);
9356974a6fSJohn Johansen 
9456974a6fSJohn Johansen 		if (aad(sa)->denied & NET_PERMS_MASK) {
9556974a6fSJohn Johansen 			audit_log_format(ab, " denied_mask=");
9656974a6fSJohn Johansen 			aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0,
9756974a6fSJohn Johansen 					   net_mask_names, NET_PERMS_MASK);
9856974a6fSJohn Johansen 		}
9956974a6fSJohn Johansen 	}
10056974a6fSJohn Johansen 	if (aad(sa)->peer) {
10156974a6fSJohn Johansen 		audit_log_format(ab, " peer=");
10256974a6fSJohn Johansen 		aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
10356974a6fSJohn Johansen 				FLAGS_NONE, GFP_ATOMIC);
10456974a6fSJohn Johansen 	}
10556974a6fSJohn Johansen }
10656974a6fSJohn Johansen 
10756974a6fSJohn Johansen /* Generic af perm */
10856974a6fSJohn Johansen int aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
10956974a6fSJohn Johansen 		       u32 request, u16 family, int type)
11056974a6fSJohn Johansen {
11156974a6fSJohn Johansen 	struct aa_perms perms = { };
11256974a6fSJohn Johansen 	unsigned int state;
11356974a6fSJohn Johansen 	__be16 buffer[2];
11456974a6fSJohn Johansen 
11556974a6fSJohn Johansen 	AA_BUG(family >= AF_MAX);
11656974a6fSJohn Johansen 	AA_BUG(type < 0 || type >= SOCK_MAX);
11756974a6fSJohn Johansen 
11856974a6fSJohn Johansen 	if (profile_unconfined(profile))
11956974a6fSJohn Johansen 		return 0;
12056974a6fSJohn Johansen 	state = PROFILE_MEDIATES(profile, AA_CLASS_NET);
12156974a6fSJohn Johansen 	if (!state)
12256974a6fSJohn Johansen 		return 0;
12356974a6fSJohn Johansen 
12456974a6fSJohn Johansen 	buffer[0] = cpu_to_be16(family);
12556974a6fSJohn Johansen 	buffer[1] = cpu_to_be16((u16) type);
12656974a6fSJohn Johansen 	state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer,
12756974a6fSJohn Johansen 				 4);
12856974a6fSJohn Johansen 	aa_compute_perms(profile->policy.dfa, state, &perms);
12956974a6fSJohn Johansen 	aa_apply_modes_to_perms(profile, &perms);
13056974a6fSJohn Johansen 
13156974a6fSJohn Johansen 	return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
13256974a6fSJohn Johansen }
13356974a6fSJohn Johansen 
13456974a6fSJohn Johansen int aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
13556974a6fSJohn Johansen 	       int type, int protocol)
13656974a6fSJohn Johansen {
13756974a6fSJohn Johansen 	struct aa_profile *profile;
13856974a6fSJohn Johansen 	DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol);
13956974a6fSJohn Johansen 
14056974a6fSJohn Johansen 	return fn_for_each_confined(label, profile,
14156974a6fSJohn Johansen 			aa_profile_af_perm(profile, &sa, request, family,
14256974a6fSJohn Johansen 					   type));
14356974a6fSJohn Johansen }
14456974a6fSJohn Johansen 
14556974a6fSJohn Johansen static int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request,
14656974a6fSJohn Johansen 			    struct sock *sk)
14756974a6fSJohn Johansen {
1485f997580STony Jones 	int error = 0;
14956974a6fSJohn Johansen 
15056974a6fSJohn Johansen 	AA_BUG(!label);
15156974a6fSJohn Johansen 	AA_BUG(!sk);
15256974a6fSJohn Johansen 
1535f997580STony Jones 	if (!unconfined(label)) {
1545f997580STony Jones 		struct aa_profile *profile;
1555f997580STony Jones 		DEFINE_AUDIT_SK(sa, op, sk);
15656974a6fSJohn Johansen 
1575f997580STony Jones 		error = fn_for_each_confined(label, profile,
15856974a6fSJohn Johansen 			    aa_profile_af_sk_perm(profile, &sa, request, sk));
15956974a6fSJohn Johansen 	}
16056974a6fSJohn Johansen 
1615f997580STony Jones 	return error;
1625f997580STony Jones }
1635f997580STony Jones 
16456974a6fSJohn Johansen int aa_sk_perm(const char *op, u32 request, struct sock *sk)
16556974a6fSJohn Johansen {
16656974a6fSJohn Johansen 	struct aa_label *label;
16756974a6fSJohn Johansen 	int error;
16856974a6fSJohn Johansen 
16956974a6fSJohn Johansen 	AA_BUG(!sk);
17056974a6fSJohn Johansen 	AA_BUG(in_interrupt());
17156974a6fSJohn Johansen 
17256974a6fSJohn Johansen 	/* TODO: switch to begin_current_label ???? */
17356974a6fSJohn Johansen 	label = begin_current_label_crit_section();
17456974a6fSJohn Johansen 	error = aa_label_sk_perm(label, op, request, sk);
17556974a6fSJohn Johansen 	end_current_label_crit_section(label);
17656974a6fSJohn Johansen 
17756974a6fSJohn Johansen 	return error;
17856974a6fSJohn Johansen }
17956974a6fSJohn Johansen 
18056974a6fSJohn Johansen 
18156974a6fSJohn Johansen int aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
18256974a6fSJohn Johansen 		      struct socket *sock)
18356974a6fSJohn Johansen {
18456974a6fSJohn Johansen 	AA_BUG(!label);
18556974a6fSJohn Johansen 	AA_BUG(!sock);
18656974a6fSJohn Johansen 	AA_BUG(!sock->sk);
18756974a6fSJohn Johansen 
18856974a6fSJohn Johansen 	return aa_label_sk_perm(label, op, request, sock->sk);
18956974a6fSJohn Johansen }
190ab9f2115SMatthew Garrett 
191e1af4779SArnd Bergmann #ifdef CONFIG_NETWORK_SECMARK
192ab9f2115SMatthew Garrett static int apparmor_secmark_init(struct aa_secmark *secmark)
193ab9f2115SMatthew Garrett {
194ab9f2115SMatthew Garrett 	struct aa_label *label;
195ab9f2115SMatthew Garrett 
196ab9f2115SMatthew Garrett 	if (secmark->label[0] == '*') {
197ab9f2115SMatthew Garrett 		secmark->secid = AA_SECID_WILDCARD;
198ab9f2115SMatthew Garrett 		return 0;
199ab9f2115SMatthew Garrett 	}
200ab9f2115SMatthew Garrett 
201ab9f2115SMatthew Garrett 	label = aa_label_strn_parse(&root_ns->unconfined->label,
202ab9f2115SMatthew Garrett 				    secmark->label, strlen(secmark->label),
203ab9f2115SMatthew Garrett 				    GFP_ATOMIC, false, false);
204ab9f2115SMatthew Garrett 
205ab9f2115SMatthew Garrett 	if (IS_ERR(label))
206ab9f2115SMatthew Garrett 		return PTR_ERR(label);
207ab9f2115SMatthew Garrett 
208ab9f2115SMatthew Garrett 	secmark->secid = label->secid;
209ab9f2115SMatthew Garrett 
210ab9f2115SMatthew Garrett 	return 0;
211ab9f2115SMatthew Garrett }
212ab9f2115SMatthew Garrett 
213ab9f2115SMatthew Garrett static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
214ab9f2115SMatthew Garrett 			   struct common_audit_data *sa, struct sock *sk)
215ab9f2115SMatthew Garrett {
216ab9f2115SMatthew Garrett 	int i, ret;
217ab9f2115SMatthew Garrett 	struct aa_perms perms = { };
218ab9f2115SMatthew Garrett 
219ab9f2115SMatthew Garrett 	if (profile->secmark_count == 0)
220ab9f2115SMatthew Garrett 		return 0;
221ab9f2115SMatthew Garrett 
222ab9f2115SMatthew Garrett 	for (i = 0; i < profile->secmark_count; i++) {
223ab9f2115SMatthew Garrett 		if (!profile->secmark[i].secid) {
224ab9f2115SMatthew Garrett 			ret = apparmor_secmark_init(&profile->secmark[i]);
225ab9f2115SMatthew Garrett 			if (ret)
226ab9f2115SMatthew Garrett 				return ret;
227ab9f2115SMatthew Garrett 		}
228ab9f2115SMatthew Garrett 
229ab9f2115SMatthew Garrett 		if (profile->secmark[i].secid == secid ||
230ab9f2115SMatthew Garrett 		    profile->secmark[i].secid == AA_SECID_WILDCARD) {
231ab9f2115SMatthew Garrett 			if (profile->secmark[i].deny)
232ab9f2115SMatthew Garrett 				perms.deny = ALL_PERMS_MASK;
233ab9f2115SMatthew Garrett 			else
234ab9f2115SMatthew Garrett 				perms.allow = ALL_PERMS_MASK;
235ab9f2115SMatthew Garrett 
236ab9f2115SMatthew Garrett 			if (profile->secmark[i].audit)
237ab9f2115SMatthew Garrett 				perms.audit = ALL_PERMS_MASK;
238ab9f2115SMatthew Garrett 		}
239ab9f2115SMatthew Garrett 	}
240ab9f2115SMatthew Garrett 
241ab9f2115SMatthew Garrett 	aa_apply_modes_to_perms(profile, &perms);
242ab9f2115SMatthew Garrett 
243ab9f2115SMatthew Garrett 	return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
244ab9f2115SMatthew Garrett }
245ab9f2115SMatthew Garrett 
246ab9f2115SMatthew Garrett int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
247ab9f2115SMatthew Garrett 			   u32 secid, struct sock *sk)
248ab9f2115SMatthew Garrett {
249ab9f2115SMatthew Garrett 	struct aa_profile *profile;
250ab9f2115SMatthew Garrett 	DEFINE_AUDIT_SK(sa, op, sk);
251ab9f2115SMatthew Garrett 
252ab9f2115SMatthew Garrett 	return fn_for_each_confined(label, profile,
253ab9f2115SMatthew Garrett 				    aa_secmark_perm(profile, request, secid,
254ab9f2115SMatthew Garrett 						    &sa, sk));
255ab9f2115SMatthew Garrett }
256e1af4779SArnd Bergmann #endif
257