162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AppArmor security module
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This file contains AppArmor network mediation
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE
862306a36Sopenharmony_ci * Copyright 2009-2017 Canonical Ltd.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "include/apparmor.h"
1262306a36Sopenharmony_ci#include "include/audit.h"
1362306a36Sopenharmony_ci#include "include/cred.h"
1462306a36Sopenharmony_ci#include "include/label.h"
1562306a36Sopenharmony_ci#include "include/net.h"
1662306a36Sopenharmony_ci#include "include/policy.h"
1762306a36Sopenharmony_ci#include "include/secid.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include "net_names.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistruct aa_sfs_entry aa_sfs_entry_network[] = {
2362306a36Sopenharmony_ci	AA_SFS_FILE_STRING("af_mask",	AA_SFS_AF_MASK),
2462306a36Sopenharmony_ci	{ }
2562306a36Sopenharmony_ci};
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic const char * const net_mask_names[] = {
2862306a36Sopenharmony_ci	"unknown",
2962306a36Sopenharmony_ci	"send",
3062306a36Sopenharmony_ci	"receive",
3162306a36Sopenharmony_ci	"unknown",
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	"create",
3462306a36Sopenharmony_ci	"shutdown",
3562306a36Sopenharmony_ci	"connect",
3662306a36Sopenharmony_ci	"unknown",
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	"setattr",
3962306a36Sopenharmony_ci	"getattr",
4062306a36Sopenharmony_ci	"setcred",
4162306a36Sopenharmony_ci	"getcred",
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	"chmod",
4462306a36Sopenharmony_ci	"chown",
4562306a36Sopenharmony_ci	"chgrp",
4662306a36Sopenharmony_ci	"lock",
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	"mmap",
4962306a36Sopenharmony_ci	"mprot",
5062306a36Sopenharmony_ci	"unknown",
5162306a36Sopenharmony_ci	"unknown",
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	"accept",
5462306a36Sopenharmony_ci	"bind",
5562306a36Sopenharmony_ci	"listen",
5662306a36Sopenharmony_ci	"unknown",
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	"setopt",
5962306a36Sopenharmony_ci	"getopt",
6062306a36Sopenharmony_ci	"unknown",
6162306a36Sopenharmony_ci	"unknown",
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	"unknown",
6462306a36Sopenharmony_ci	"unknown",
6562306a36Sopenharmony_ci	"unknown",
6662306a36Sopenharmony_ci	"unknown",
6762306a36Sopenharmony_ci};
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* audit callback for net specific fields */
7162306a36Sopenharmony_civoid audit_net_cb(struct audit_buffer *ab, void *va)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct common_audit_data *sa = va;
7462306a36Sopenharmony_ci	struct apparmor_audit_data *ad = aad(sa);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (address_family_names[sa->u.net->family])
7762306a36Sopenharmony_ci		audit_log_format(ab, " family=\"%s\"",
7862306a36Sopenharmony_ci				 address_family_names[sa->u.net->family]);
7962306a36Sopenharmony_ci	else
8062306a36Sopenharmony_ci		audit_log_format(ab, " family=\"unknown(%d)\"",
8162306a36Sopenharmony_ci				 sa->u.net->family);
8262306a36Sopenharmony_ci	if (sock_type_names[ad->net.type])
8362306a36Sopenharmony_ci		audit_log_format(ab, " sock_type=\"%s\"",
8462306a36Sopenharmony_ci				 sock_type_names[ad->net.type]);
8562306a36Sopenharmony_ci	else
8662306a36Sopenharmony_ci		audit_log_format(ab, " sock_type=\"unknown(%d)\"",
8762306a36Sopenharmony_ci				 ad->net.type);
8862306a36Sopenharmony_ci	audit_log_format(ab, " protocol=%d", ad->net.protocol);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	if (ad->request & NET_PERMS_MASK) {
9162306a36Sopenharmony_ci		audit_log_format(ab, " requested_mask=");
9262306a36Sopenharmony_ci		aa_audit_perm_mask(ab, ad->request, NULL, 0,
9362306a36Sopenharmony_ci				   net_mask_names, NET_PERMS_MASK);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci		if (ad->denied & NET_PERMS_MASK) {
9662306a36Sopenharmony_ci			audit_log_format(ab, " denied_mask=");
9762306a36Sopenharmony_ci			aa_audit_perm_mask(ab, ad->denied, NULL, 0,
9862306a36Sopenharmony_ci					   net_mask_names, NET_PERMS_MASK);
9962306a36Sopenharmony_ci		}
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci	if (ad->peer) {
10262306a36Sopenharmony_ci		audit_log_format(ab, " peer=");
10362306a36Sopenharmony_ci		aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
10462306a36Sopenharmony_ci				FLAGS_NONE, GFP_ATOMIC);
10562306a36Sopenharmony_ci	}
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci/* Generic af perm */
10962306a36Sopenharmony_ciint aa_profile_af_perm(struct aa_profile *profile,
11062306a36Sopenharmony_ci		       struct apparmor_audit_data *ad, u32 request, u16 family,
11162306a36Sopenharmony_ci		       int type)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct aa_ruleset *rules = list_first_entry(&profile->rules,
11462306a36Sopenharmony_ci						    typeof(*rules), list);
11562306a36Sopenharmony_ci	struct aa_perms perms = { };
11662306a36Sopenharmony_ci	aa_state_t state;
11762306a36Sopenharmony_ci	__be16 buffer[2];
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	AA_BUG(family >= AF_MAX);
12062306a36Sopenharmony_ci	AA_BUG(type < 0 || type >= SOCK_MAX);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	if (profile_unconfined(profile))
12362306a36Sopenharmony_ci		return 0;
12462306a36Sopenharmony_ci	state = RULE_MEDIATES(rules, AA_CLASS_NET);
12562306a36Sopenharmony_ci	if (!state)
12662306a36Sopenharmony_ci		return 0;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	buffer[0] = cpu_to_be16(family);
12962306a36Sopenharmony_ci	buffer[1] = cpu_to_be16((u16) type);
13062306a36Sopenharmony_ci	state = aa_dfa_match_len(rules->policy.dfa, state, (char *) &buffer,
13162306a36Sopenharmony_ci				 4);
13262306a36Sopenharmony_ci	perms = *aa_lookup_perms(&rules->policy, state);
13362306a36Sopenharmony_ci	aa_apply_modes_to_perms(profile, &perms);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return aa_check_perms(profile, &perms, request, ad, audit_net_cb);
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ciint aa_af_perm(const struct cred *subj_cred, struct aa_label *label,
13962306a36Sopenharmony_ci	       const char *op, u32 request, u16 family, int type, int protocol)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	struct aa_profile *profile;
14262306a36Sopenharmony_ci	DEFINE_AUDIT_NET(ad, op, NULL, family, type, protocol);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return fn_for_each_confined(label, profile,
14562306a36Sopenharmony_ci			aa_profile_af_perm(profile, &ad, request, family,
14662306a36Sopenharmony_ci					   type));
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int aa_label_sk_perm(const struct cred *subj_cred,
15062306a36Sopenharmony_ci			    struct aa_label *label,
15162306a36Sopenharmony_ci			    const char *op, u32 request,
15262306a36Sopenharmony_ci			    struct sock *sk)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct aa_sk_ctx *ctx = SK_CTX(sk);
15562306a36Sopenharmony_ci	int error = 0;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	AA_BUG(!label);
15862306a36Sopenharmony_ci	AA_BUG(!sk);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	if (ctx->label != kernel_t && !unconfined(label)) {
16162306a36Sopenharmony_ci		struct aa_profile *profile;
16262306a36Sopenharmony_ci		DEFINE_AUDIT_SK(ad, op, sk);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci		ad.subj_cred = subj_cred;
16562306a36Sopenharmony_ci		error = fn_for_each_confined(label, profile,
16662306a36Sopenharmony_ci			    aa_profile_af_sk_perm(profile, &ad, request, sk));
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	return error;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ciint aa_sk_perm(const char *op, u32 request, struct sock *sk)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	struct aa_label *label;
17562306a36Sopenharmony_ci	int error;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	AA_BUG(!sk);
17862306a36Sopenharmony_ci	AA_BUG(in_interrupt());
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	/* TODO: switch to begin_current_label ???? */
18162306a36Sopenharmony_ci	label = begin_current_label_crit_section();
18262306a36Sopenharmony_ci	error = aa_label_sk_perm(current_cred(), label, op, request, sk);
18362306a36Sopenharmony_ci	end_current_label_crit_section(label);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return error;
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ciint aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label,
19062306a36Sopenharmony_ci		      const char *op, u32 request, struct socket *sock)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	AA_BUG(!label);
19362306a36Sopenharmony_ci	AA_BUG(!sock);
19462306a36Sopenharmony_ci	AA_BUG(!sock->sk);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	return aa_label_sk_perm(subj_cred, label, op, request, sock->sk);
19762306a36Sopenharmony_ci}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK
20062306a36Sopenharmony_cistatic int apparmor_secmark_init(struct aa_secmark *secmark)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct aa_label *label;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	if (secmark->label[0] == '*') {
20562306a36Sopenharmony_ci		secmark->secid = AA_SECID_WILDCARD;
20662306a36Sopenharmony_ci		return 0;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	label = aa_label_strn_parse(&root_ns->unconfined->label,
21062306a36Sopenharmony_ci				    secmark->label, strlen(secmark->label),
21162306a36Sopenharmony_ci				    GFP_ATOMIC, false, false);
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	if (IS_ERR(label))
21462306a36Sopenharmony_ci		return PTR_ERR(label);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	secmark->secid = label->secid;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	return 0;
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
22262306a36Sopenharmony_ci			   struct apparmor_audit_data *ad)
22362306a36Sopenharmony_ci{
22462306a36Sopenharmony_ci	int i, ret;
22562306a36Sopenharmony_ci	struct aa_perms perms = { };
22662306a36Sopenharmony_ci	struct aa_ruleset *rules = list_first_entry(&profile->rules,
22762306a36Sopenharmony_ci						    typeof(*rules), list);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	if (rules->secmark_count == 0)
23062306a36Sopenharmony_ci		return 0;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	for (i = 0; i < rules->secmark_count; i++) {
23362306a36Sopenharmony_ci		if (!rules->secmark[i].secid) {
23462306a36Sopenharmony_ci			ret = apparmor_secmark_init(&rules->secmark[i]);
23562306a36Sopenharmony_ci			if (ret)
23662306a36Sopenharmony_ci				return ret;
23762306a36Sopenharmony_ci		}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci		if (rules->secmark[i].secid == secid ||
24062306a36Sopenharmony_ci		    rules->secmark[i].secid == AA_SECID_WILDCARD) {
24162306a36Sopenharmony_ci			if (rules->secmark[i].deny)
24262306a36Sopenharmony_ci				perms.deny = ALL_PERMS_MASK;
24362306a36Sopenharmony_ci			else
24462306a36Sopenharmony_ci				perms.allow = ALL_PERMS_MASK;
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci			if (rules->secmark[i].audit)
24762306a36Sopenharmony_ci				perms.audit = ALL_PERMS_MASK;
24862306a36Sopenharmony_ci		}
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	aa_apply_modes_to_perms(profile, &perms);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	return aa_check_perms(profile, &perms, request, ad, audit_net_cb);
25462306a36Sopenharmony_ci}
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ciint apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
25762306a36Sopenharmony_ci			   u32 secid, const struct sock *sk)
25862306a36Sopenharmony_ci{
25962306a36Sopenharmony_ci	struct aa_profile *profile;
26062306a36Sopenharmony_ci	DEFINE_AUDIT_SK(ad, op, sk);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	return fn_for_each_confined(label, profile,
26362306a36Sopenharmony_ci				    aa_secmark_perm(profile, request, secid,
26462306a36Sopenharmony_ci						    &ad));
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci#endif
267