File Index
Files and directories
Sign in
FILE

net.c

File preview with syntax highlighting.

linux-6.19.14/security/apparmor/net.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * AppArmor security module
  4 *
  5 * This file contains AppArmor network mediation
  6 *
  7 * Copyright (C) 1998-2008 Novell/SUSE
  8 * Copyright 2009-2017 Canonical Ltd.
  9 */
 10
 11#include "include/af_unix.h"
 12#include "include/apparmor.h"
 13#include "include/audit.h"
 14#include "include/cred.h"
 15#include "include/label.h"
 16#include "include/net.h"
 17#include "include/policy.h"
 18#include "include/secid.h"
 19
 20#include "net_names.h"
 21
 22
 23struct aa_sfs_entry aa_sfs_entry_network[] = {
 24	AA_SFS_FILE_STRING("af_mask",	AA_SFS_AF_MASK),
 25	{ }
 26};
 27
 28struct aa_sfs_entry aa_sfs_entry_networkv9[] = {
 29	AA_SFS_FILE_STRING("af_mask",	AA_SFS_AF_MASK),
 30	AA_SFS_FILE_BOOLEAN("af_unix",	1),
 31	{ }
 32};
 33
 34static const char * const net_mask_names[] = {
 35	"unknown",
 36	"send",
 37	"receive",
 38	"unknown",
 39
 40	"create",
 41	"shutdown",
 42	"connect",
 43	"unknown",
 44
 45	"setattr",
 46	"getattr",
 47	"setcred",
 48	"getcred",
 49
 50	"chmod",
 51	"chown",
 52	"chgrp",
 53	"lock",
 54
 55	"mmap",
 56	"mprot",
 57	"unknown",
 58	"unknown",
 59
 60	"accept",
 61	"bind",
 62	"listen",
 63	"unknown",
 64
 65	"setopt",
 66	"getopt",
 67	"unknown",
 68	"unknown",
 69
 70	"unknown",
 71	"unknown",
 72	"unknown",
 73	"unknown",
 74};
 75
 76static void audit_unix_addr(struct audit_buffer *ab, const char *str,
 77			    struct sockaddr_un *addr, int addrlen)
 78{
 79	int len = unix_addr_len(addrlen);
 80
 81	if (!addr || len <= 0) {
 82		audit_log_format(ab, " %s=none", str);
 83	} else if (addr->sun_path[0]) {
 84		audit_log_format(ab, " %s=", str);
 85		audit_log_untrustedstring(ab, addr->sun_path);
 86	} else {
 87		audit_log_format(ab, " %s=\"@", str);
 88		if (audit_string_contains_control(&addr->sun_path[1], len - 1))
 89			audit_log_n_hex(ab, &addr->sun_path[1], len - 1);
 90		else
 91			audit_log_format(ab, "%.*s", len - 1,
 92					 &addr->sun_path[1]);
 93		audit_log_format(ab, "\"");
 94	}
 95}
 96
 97static void audit_unix_sk_addr(struct audit_buffer *ab, const char *str,
 98			       const struct sock *sk)
 99{
100	const struct unix_sock *u = unix_sk(sk);
101
102	if (u && u->addr) {
103		int addrlen;
104		struct sockaddr_un *addr = aa_sunaddr(u, &addrlen);
105
106		audit_unix_addr(ab, str, addr, addrlen);
107	} else {
108		audit_unix_addr(ab, str, NULL, 0);
109
110	}
111}
112
113/* audit callback for net specific fields */
114void audit_net_cb(struct audit_buffer *ab, void *va)
115{
116	struct common_audit_data *sa = va;
117	struct apparmor_audit_data *ad = aad(sa);
118
119	if (address_family_names[ad->common.u.net->family])
120		audit_log_format(ab, " family=\"%s\"",
121				 address_family_names[ad->common.u.net->family]);
122	else
123		audit_log_format(ab, " family=\"unknown(%d)\"",
124				 ad->common.u.net->family);
125	if (sock_type_names[ad->net.type])
126		audit_log_format(ab, " sock_type=\"%s\"",
127				 sock_type_names[ad->net.type]);
128	else
129		audit_log_format(ab, " sock_type=\"unknown(%d)\"",
130				 ad->net.type);
131	audit_log_format(ab, " protocol=%d", ad->net.protocol);
132
133	if (ad->request & NET_PERMS_MASK) {
134		audit_log_format(ab, " requested_mask=");
135		aa_audit_perm_mask(ab, ad->request, NULL, 0,
136				   net_mask_names, NET_PERMS_MASK);
137
138		if (ad->denied & NET_PERMS_MASK) {
139			audit_log_format(ab, " denied_mask=");
140			aa_audit_perm_mask(ab, ad->denied, NULL, 0,
141					   net_mask_names, NET_PERMS_MASK);
142		}
143	}
144	if (ad->common.u.net->family == PF_UNIX) {
145		if (ad->net.addr || !ad->common.u.net->sk)
146			audit_unix_addr(ab, "addr",
147					unix_addr(ad->net.addr),
148					ad->net.addrlen);
149		else
150			audit_unix_sk_addr(ab, "addr", ad->common.u.net->sk);
151		if (ad->request & NET_PEER_MASK) {
152			audit_unix_addr(ab, "peer_addr",
153					unix_addr(ad->net.peer.addr),
154					ad->net.peer.addrlen);
155		}
156	}
157	if (ad->peer) {
158		audit_log_format(ab, " peer=");
159		aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
160				FLAGS_NONE, GFP_ATOMIC);
161	}
162}
163
164/* standard permission lookup pattern - supports early bailout */
165int aa_do_perms(struct aa_profile *profile, struct aa_policydb *policy,
166		aa_state_t state, u32 request,
167		struct aa_perms *p, struct apparmor_audit_data *ad)
168{
169	struct aa_perms perms;
170
171	AA_BUG(!profile);
172	AA_BUG(!policy);
173
174
175	if (state || !p)
176		p = aa_lookup_perms(policy, state);
177	perms = *p;
178	aa_apply_modes_to_perms(profile, &perms);
179	return aa_check_perms(profile, &perms, request, ad,
180			      audit_net_cb);
181}
182
183/* only continue match if
184 *   insufficient current perms at current state
185 *   indicates there are more perms in later state
186 * Returns: perms struct if early match
187 */
188static struct aa_perms *early_match(struct aa_policydb *policy,
189				    aa_state_t state, u32 request)
190{
191	struct aa_perms *p;
192
193	p = aa_lookup_perms(policy, state);
194	if (((p->allow & request) != request) && (p->allow & AA_CONT_MATCH))
195		return NULL;
196	return p;
197}
198
199static aa_state_t aa_dfa_match_be16(struct aa_dfa *dfa, aa_state_t state,
200					  u16 data)
201{
202	__be16 buffer = cpu_to_be16(data);
203
204	return aa_dfa_match_len(dfa, state, (char *) &buffer, 2);
205}
206
207/**
208 * aa_match_to_prot - match the af, type, protocol triplet
209 * @policy: policy being matched
210 * @state: state to start in
211 * @request: permissions being requested, ignored if @p == NULL
212 * @af: socket address family
213 * @type: socket type
214 * @protocol: socket protocol
215 * @p: output - pointer to permission associated with match
216 * @info: output - pointer to string describing failure
217 *
218 * RETURNS: state match stopped in.
219 *
220 * If @(p) is assigned a value the returned state will be the
221 * corresponding state. Will not set @p on failure or if match completes
222 * only if an early match occurs
223 */
224aa_state_t aa_match_to_prot(struct aa_policydb *policy, aa_state_t state,
225			    u32 request, u16 af, int type, int protocol,
226			    struct aa_perms **p, const char **info)
227{
228	state = aa_dfa_match_be16(policy->dfa, state, (u16)af);
229	if (!state) {
230		*info = "failed af match";
231		return state;
232	}
233	state = aa_dfa_match_be16(policy->dfa, state, (u16)type);
234	if (state) {
235		if (p)
236			*p = early_match(policy, state, request);
237		if (!p || !*p) {
238			state = aa_dfa_match_be16(policy->dfa, state, (u16)protocol);
239			if (!state)
240				*info = "failed protocol match";
241		}
242	} else {
243		*info = "failed type match";
244	}
245
246	return state;
247}
248
249/* Generic af perm */
250int aa_profile_af_perm(struct aa_profile *profile,
251		       struct apparmor_audit_data *ad, u32 request, u16 family,
252		       int type, int protocol)
253{
254	struct aa_ruleset *rules = profile->label.rules[0];
255	struct aa_perms *p = NULL;
256	aa_state_t state;
257
258	AA_BUG(family >= AF_MAX);
259	AA_BUG(type < 0 || type >= SOCK_MAX);
260	AA_BUG(profile_unconfined(profile));
261
262	if (profile_unconfined(profile))
263		return 0;
264	state = RULE_MEDIATES_NET(rules);
265	if (!state)
266		return 0;
267	state = aa_match_to_prot(rules->policy, state, request, family, type,
268				 protocol, &p, &ad->info);
269	return aa_do_perms(profile, rules->policy, state, request, p, ad);
270}
271
272int aa_af_perm(const struct cred *subj_cred, struct aa_label *label,
273	       const char *op, u32 request, u16 family, int type, int protocol)
274{
275	struct aa_profile *profile;
276	DEFINE_AUDIT_NET(ad, op, subj_cred, NULL, family, type, protocol);
277
278	return fn_for_each_confined(label, profile,
279			aa_profile_af_perm(profile, &ad, request, family,
280					   type, protocol));
281}
282
283static int aa_label_sk_perm(const struct cred *subj_cred,
284			    struct aa_label *label,
285			    const char *op, u32 request,
286			    struct sock *sk)
287{
288	struct aa_sk_ctx *ctx = aa_sock(sk);
289	int error = 0;
290
291	AA_BUG(!label);
292	AA_BUG(!sk);
293
294	if (rcu_access_pointer(ctx->label) != kernel_t && !unconfined(label)) {
295		struct aa_profile *profile;
296		DEFINE_AUDIT_SK(ad, op, subj_cred, sk);
297
298		ad.subj_cred = subj_cred;
299		error = fn_for_each_confined(label, profile,
300			    aa_profile_af_sk_perm(profile, &ad, request, sk));
301	}
302
303	return error;
304}
305
306int aa_sk_perm(const char *op, u32 request, struct sock *sk)
307{
308	struct aa_label *label;
309	int error;
310
311	AA_BUG(!sk);
312	AA_BUG(in_interrupt());
313
314	/* TODO: switch to begin_current_label ???? */
315	label = begin_current_label_crit_section();
316	error = aa_label_sk_perm(current_cred(), label, op, request, sk);
317	end_current_label_crit_section(label);
318
319	return error;
320}
321
322
323int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label,
324		      const char *op, u32 request, struct file *file)
325{
326	struct socket *sock = (struct socket *) file->private_data;
327
328	AA_BUG(!label);
329
330	/* sock && sock->sk can be NULL for sockets being set up or torn down */
331	if (!sock || !sock->sk)
332		return 0;
333
334	if (sock->sk->sk_family == PF_UNIX)
335		return aa_unix_file_perm(subj_cred, label, op, request, file);
336	return aa_label_sk_perm(subj_cred, label, op, request, sock->sk);
337}
338
339#ifdef CONFIG_NETWORK_SECMARK
340static int apparmor_secmark_init(struct aa_secmark *secmark)
341{
342	struct aa_label *label;
343
344	if (secmark->label[0] == '*') {
345		secmark->secid = AA_SECID_WILDCARD;
346		return 0;
347	}
348
349	label = aa_label_strn_parse(&root_ns->unconfined->label,
350				    secmark->label, strlen(secmark->label),
351				    GFP_ATOMIC, false, false);
352
353	if (IS_ERR(label))
354		return PTR_ERR(label);
355
356	secmark->secid = label->secid;
357
358	return 0;
359}
360
361static int aa_secmark_perm(struct aa_profile *profile, u32 request, u32 secid,
362			   struct apparmor_audit_data *ad)
363{
364	int i, ret;
365	struct aa_perms perms = { };
366	struct aa_ruleset *rules = profile->label.rules[0];
367
368	if (rules->secmark_count == 0)
369		return 0;
370
371	for (i = 0; i < rules->secmark_count; i++) {
372		if (!rules->secmark[i].secid) {
373			ret = apparmor_secmark_init(&rules->secmark[i]);
374			if (ret)
375				return ret;
376		}
377
378		if (rules->secmark[i].secid == secid ||
379		    rules->secmark[i].secid == AA_SECID_WILDCARD) {
380			if (rules->secmark[i].deny)
381				perms.deny = ALL_PERMS_MASK;
382			else
383				perms.allow = ALL_PERMS_MASK;
384
385			if (rules->secmark[i].audit)
386				perms.audit = ALL_PERMS_MASK;
387		}
388	}
389
390	aa_apply_modes_to_perms(profile, &perms);
391
392	return aa_check_perms(profile, &perms, request, ad, audit_net_cb);
393}
394
395int apparmor_secmark_check(struct aa_label *label, char *op, u32 request,
396			   u32 secid, const struct sock *sk)
397{
398	struct aa_profile *profile;
399	DEFINE_AUDIT_SK(ad, op, NULL, sk);
400
401	return fn_for_each_confined(label, profile,
402				    aa_secmark_perm(profile, request, secid,
403						    &ad));
404}
405#endif
~/ Read-only file preview.