18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * AppArmor security module
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This file contains AppArmor network mediation
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE
88c2ecf20Sopenharmony_ci * Copyright 2009-2017 Canonical Ltd.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "include/apparmor.h"
128c2ecf20Sopenharmony_ci#include "include/audit.h"
138c2ecf20Sopenharmony_ci#include "include/cred.h"
148c2ecf20Sopenharmony_ci#include "include/label.h"
158c2ecf20Sopenharmony_ci#include "include/net.h"
168c2ecf20Sopenharmony_ci#include "include/policy.h"
178c2ecf20Sopenharmony_ci#include "include/secid.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "net_names.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_cistruct aa_sfs_entry aa_sfs_entry_network[] = {
238c2ecf20Sopenharmony_ci	AA_SFS_FILE_STRING("af_mask",	AA_SFS_AF_MASK),
248c2ecf20Sopenharmony_ci	{ }
258c2ecf20Sopenharmony_ci};
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic const char * const net_mask_names[] = {
288c2ecf20Sopenharmony_ci	"unknown",
298c2ecf20Sopenharmony_ci	"send",
308c2ecf20Sopenharmony_ci	"receive",
318c2ecf20Sopenharmony_ci	"unknown",
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci	"create",
348c2ecf20Sopenharmony_ci	"shutdown",
358c2ecf20Sopenharmony_ci	"connect",
368c2ecf20Sopenharmony_ci	"unknown",
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	"setattr",
398c2ecf20Sopenharmony_ci	"getattr",
408c2ecf20Sopenharmony_ci	"setcred",
418c2ecf20Sopenharmony_ci	"getcred",
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	"chmod",
448c2ecf20Sopenharmony_ci	"chown",
458c2ecf20Sopenharmony_ci	"chgrp",
468c2ecf20Sopenharmony_ci	"lock",
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	"mmap",
498c2ecf20Sopenharmony_ci	"mprot",
508c2ecf20Sopenharmony_ci	"unknown",
518c2ecf20Sopenharmony_ci	"unknown",
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	"accept",
548c2ecf20Sopenharmony_ci	"bind",
558c2ecf20Sopenharmony_ci	"listen",
568c2ecf20Sopenharmony_ci	"unknown",
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	"setopt",
598c2ecf20Sopenharmony_ci	"getopt",
608c2ecf20Sopenharmony_ci	"unknown",
618c2ecf20Sopenharmony_ci	"unknown",
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	"unknown",
648c2ecf20Sopenharmony_ci	"unknown",
658c2ecf20Sopenharmony_ci	"unknown",
668c2ecf20Sopenharmony_ci	"unknown",
678c2ecf20Sopenharmony_ci};
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci/* audit callback for net specific fields */
718c2ecf20Sopenharmony_civoid audit_net_cb(struct audit_buffer *ab, void *va)
728c2ecf20Sopenharmony_ci{
738c2ecf20Sopenharmony_ci	struct common_audit_data *sa = va;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	if (address_family_names[sa->u.net->family])
768c2ecf20Sopenharmony_ci		audit_log_format(ab, " family=\"%s\"",
778c2ecf20Sopenharmony_ci				 address_family_names[sa->u.net->family]);
788c2ecf20Sopenharmony_ci	else
798c2ecf20Sopenharmony_ci		audit_log_format(ab, " family=\"unknown(%d)\"",
808c2ecf20Sopenharmony_ci				 sa->u.net->family);
818c2ecf20Sopenharmony_ci	if (sock_type_names[aad(sa)->net.type])
828c2ecf20Sopenharmony_ci		audit_log_format(ab, " sock_type=\"%s\"",
838c2ecf20Sopenharmony_ci				 sock_type_names[aad(sa)->net.type]);
848c2ecf20Sopenharmony_ci	else
858c2ecf20Sopenharmony_ci		audit_log_format(ab, " sock_type=\"unknown(%d)\"",
868c2ecf20Sopenharmony_ci				 aad(sa)->net.type);
878c2ecf20Sopenharmony_ci	audit_log_format(ab, " protocol=%d", aad(sa)->net.protocol);
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	if (aad(sa)->request & NET_PERMS_MASK) {
908c2ecf20Sopenharmony_ci		audit_log_format(ab, " requested_mask=");
918c2ecf20Sopenharmony_ci		aa_audit_perm_mask(ab, aad(sa)->request, NULL, 0,
928c2ecf20Sopenharmony_ci				   net_mask_names, NET_PERMS_MASK);
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		if (aad(sa)->denied & NET_PERMS_MASK) {
958c2ecf20Sopenharmony_ci			audit_log_format(ab, " denied_mask=");
968c2ecf20Sopenharmony_ci			aa_audit_perm_mask(ab, aad(sa)->denied, NULL, 0,
978c2ecf20Sopenharmony_ci					   net_mask_names, NET_PERMS_MASK);
988c2ecf20Sopenharmony_ci		}
998c2ecf20Sopenharmony_ci	}
1008c2ecf20Sopenharmony_ci	if (aad(sa)->peer) {
1018c2ecf20Sopenharmony_ci		audit_log_format(ab, " peer=");
1028c2ecf20Sopenharmony_ci		aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
1038c2ecf20Sopenharmony_ci				FLAGS_NONE, GFP_ATOMIC);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci/* Generic af perm */
1088c2ecf20Sopenharmony_ciint aa_profile_af_perm(struct aa_profile *profile, struct common_audit_data *sa,
1098c2ecf20Sopenharmony_ci		       u32 request, u16 family, int type)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	struct aa_perms perms = { };
1128c2ecf20Sopenharmony_ci	unsigned int state;
1138c2ecf20Sopenharmony_ci	__be16 buffer[2];
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	AA_BUG(family >= AF_MAX);
1168c2ecf20Sopenharmony_ci	AA_BUG(type < 0 || type >= SOCK_MAX);
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	if (profile_unconfined(profile))
1198c2ecf20Sopenharmony_ci		return 0;
1208c2ecf20Sopenharmony_ci	state = PROFILE_MEDIATES(profile, AA_CLASS_NET);
1218c2ecf20Sopenharmony_ci	if (!state)
1228c2ecf20Sopenharmony_ci		return 0;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	buffer[0] = cpu_to_be16(family);
1258c2ecf20Sopenharmony_ci	buffer[1] = cpu_to_be16((u16) type);
1268c2ecf20Sopenharmony_ci	state = aa_dfa_match_len(profile->policy.dfa, state, (char *) &buffer,
1278c2ecf20Sopenharmony_ci				 4);
1288c2ecf20Sopenharmony_ci	aa_compute_perms(profile->policy.dfa, state, &perms);
1298c2ecf20Sopenharmony_ci	aa_apply_modes_to_perms(profile, &perms);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
1328c2ecf20Sopenharmony_ci}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ciint aa_af_perm(struct aa_label *label, const char *op, u32 request, u16 family,
1358c2ecf20Sopenharmony_ci	       int type, int protocol)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	struct aa_profile *profile;
1388c2ecf20Sopenharmony_ci	DEFINE_AUDIT_NET(sa, op, NULL, family, type, protocol);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	return fn_for_each_confined(label, profile,
1418c2ecf20Sopenharmony_ci			aa_profile_af_perm(profile, &sa, request, family,
1428c2ecf20Sopenharmony_ci					   type));
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cistatic int aa_label_sk_perm(struct aa_label *label, const char *op, u32 request,
1468c2ecf20Sopenharmony_ci			    struct sock *sk)
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	int error = 0;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	AA_BUG(!label);
1518c2ecf20Sopenharmony_ci	AA_BUG(!sk);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (!unconfined(label)) {
1548c2ecf20Sopenharmony_ci		struct aa_profile *profile;
1558c2ecf20Sopenharmony_ci		DEFINE_AUDIT_SK(sa, op, sk);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci		error = fn_for_each_confined(label, profile,
1588c2ecf20Sopenharmony_ci			    aa_profile_af_sk_perm(profile, &sa, request, sk));
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	return error;
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ciint aa_sk_perm(const char *op, u32 request, struct sock *sk)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	struct aa_label *label;
1678c2ecf20Sopenharmony_ci	int error;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	AA_BUG(!sk);
1708c2ecf20Sopenharmony_ci	AA_BUG(in_interrupt());
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	/* TODO: switch to begin_current_label ???? */
1738c2ecf20Sopenharmony_ci	label = begin_current_label_crit_section();
1748c2ecf20Sopenharmony_ci	error = aa_label_sk_perm(label, op, request, sk);
1758c2ecf20Sopenharmony_ci	end_current_label_crit_section(label);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return error;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ciint aa_sock_file_perm(struct aa_label *label, const char *op, u32 request,
1828c2ecf20Sopenharmony_ci		      struct socket *sock)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	AA_BUG(!label);
1858c2ecf20Sopenharmony_ci	AA_BUG(!sock);
1868c2ecf20Sopenharmony_ci	AA_BUG(!sock->sk);
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	return aa_label_sk_perm(label, op, request, sock->sk);
1898c2ecf20Sopenharmony_ci}
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK
1928c2ecf20Sopenharmony_cistatic int apparmor_secmark_init(struct aa_secmark *secmark)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	struct aa_label *label;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (secmark->label[0] == '*') {
1978c2ecf20Sopenharmony_ci		secmark->secid = AA_SECID_WILDCARD;
1988c2ecf20Sopenharmony_ci		return 0;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	label = aa_label_strn_parse(&root_ns->unconfined->label,
2028c2ecf20Sopenharmony_ci				    secmark->label, strlen(secmark->label),
2038c2ecf20Sopenharmony_ci				    GFP_ATOMIC, false, false);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	if (IS_ERR(label))
2068c2ecf20Sopenharmony_ci		return PTR_ERR(label);
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	secmark->secid = label->secid;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	return 0;
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
2148c2ecf20Sopenharmony_ci			   struct common_audit_data *sa, struct sock *sk)
2158c2ecf20Sopenharmony_ci{
2168c2ecf20Sopenharmony_ci	int i, ret;
2178c2ecf20Sopenharmony_ci	struct aa_perms perms = { };
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	if (profile->secmark_count == 0)
2208c2ecf20Sopenharmony_ci		return 0;
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci	for (i = 0; i < profile->secmark_count; i++) {
2238c2ecf20Sopenharmony_ci		if (!profile->secmark[i].secid) {
2248c2ecf20Sopenharmony_ci			ret = apparmor_secmark_init(&profile->secmark[i]);
2258c2ecf20Sopenharmony_ci			if (ret)
2268c2ecf20Sopenharmony_ci				return ret;
2278c2ecf20Sopenharmony_ci		}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci		if (profile->secmark[i].secid == secid ||
2308c2ecf20Sopenharmony_ci		    profile->secmark[i].secid == AA_SECID_WILDCARD) {
2318c2ecf20Sopenharmony_ci			if (profile->secmark[i].deny)
2328c2ecf20Sopenharmony_ci				perms.deny = ALL_PERMS_MASK;
2338c2ecf20Sopenharmony_ci			else
2348c2ecf20Sopenharmony_ci				perms.allow = ALL_PERMS_MASK;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci			if (profile->secmark[i].audit)
2378c2ecf20Sopenharmony_ci				perms.audit = ALL_PERMS_MASK;
2388c2ecf20Sopenharmony_ci		}
2398c2ecf20Sopenharmony_ci	}
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	aa_apply_modes_to_perms(profile, &perms);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	return aa_check_perms(profile, &perms, request, sa, audit_net_cb);
2448c2ecf20Sopenharmony_ci}
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ciint apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
2478c2ecf20Sopenharmony_ci			   u32 secid, struct sock *sk)
2488c2ecf20Sopenharmony_ci{
2498c2ecf20Sopenharmony_ci	struct aa_profile *profile;
2508c2ecf20Sopenharmony_ci	DEFINE_AUDIT_SK(sa, op, sk);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	return fn_for_each_confined(label, profile,
2538c2ecf20Sopenharmony_ci				    aa_secmark_perm(profile, request, secid,
2548c2ecf20Sopenharmony_ci						    &sa, sk));
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci#endif
257