162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AppArmor security module
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This file contains AppArmor ipc 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 <linux/gfp.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "include/audit.h"
1462306a36Sopenharmony_ci#include "include/capability.h"
1562306a36Sopenharmony_ci#include "include/cred.h"
1662306a36Sopenharmony_ci#include "include/policy.h"
1762306a36Sopenharmony_ci#include "include/ipc.h"
1862306a36Sopenharmony_ci#include "include/sig_names.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic inline int map_signal_num(int sig)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	if (sig > SIGRTMAX)
2462306a36Sopenharmony_ci		return SIGUNKNOWN;
2562306a36Sopenharmony_ci	else if (sig >= SIGRTMIN)
2662306a36Sopenharmony_ci		return sig - SIGRTMIN + SIGRT_BASE;
2762306a36Sopenharmony_ci	else if (sig < MAXMAPPED_SIG)
2862306a36Sopenharmony_ci		return sig_map[sig];
2962306a36Sopenharmony_ci	return SIGUNKNOWN;
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/**
3362306a36Sopenharmony_ci * audit_signal_mask - convert mask to permission string
3462306a36Sopenharmony_ci * @mask: permission mask to convert
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * Returns: pointer to static string
3762306a36Sopenharmony_ci */
3862306a36Sopenharmony_cistatic const char *audit_signal_mask(u32 mask)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	if (mask & MAY_READ)
4162306a36Sopenharmony_ci		return "receive";
4262306a36Sopenharmony_ci	if (mask & MAY_WRITE)
4362306a36Sopenharmony_ci		return "send";
4462306a36Sopenharmony_ci	return "";
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/**
4862306a36Sopenharmony_ci * audit_signal_cb() - call back for signal specific audit fields
4962306a36Sopenharmony_ci * @ab: audit_buffer  (NOT NULL)
5062306a36Sopenharmony_ci * @va: audit struct to audit values of  (NOT NULL)
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_cistatic void audit_signal_cb(struct audit_buffer *ab, void *va)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	struct common_audit_data *sa = va;
5562306a36Sopenharmony_ci	struct apparmor_audit_data *ad = aad(sa);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (ad->request & AA_SIGNAL_PERM_MASK) {
5862306a36Sopenharmony_ci		audit_log_format(ab, " requested_mask=\"%s\"",
5962306a36Sopenharmony_ci				 audit_signal_mask(ad->request));
6062306a36Sopenharmony_ci		if (ad->denied & AA_SIGNAL_PERM_MASK) {
6162306a36Sopenharmony_ci			audit_log_format(ab, " denied_mask=\"%s\"",
6262306a36Sopenharmony_ci					 audit_signal_mask(ad->denied));
6362306a36Sopenharmony_ci		}
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci	if (ad->signal == SIGUNKNOWN)
6662306a36Sopenharmony_ci		audit_log_format(ab, "signal=unknown(%d)",
6762306a36Sopenharmony_ci				 ad->unmappedsig);
6862306a36Sopenharmony_ci	else if (ad->signal < MAXMAPPED_SIGNAME)
6962306a36Sopenharmony_ci		audit_log_format(ab, " signal=%s", sig_names[ad->signal]);
7062306a36Sopenharmony_ci	else
7162306a36Sopenharmony_ci		audit_log_format(ab, " signal=rtmin+%d",
7262306a36Sopenharmony_ci				 ad->signal - SIGRT_BASE);
7362306a36Sopenharmony_ci	audit_log_format(ab, " peer=");
7462306a36Sopenharmony_ci	aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer,
7562306a36Sopenharmony_ci			FLAGS_NONE, GFP_ATOMIC);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic int profile_signal_perm(const struct cred *cred,
7962306a36Sopenharmony_ci			       struct aa_profile *profile,
8062306a36Sopenharmony_ci			       struct aa_label *peer, u32 request,
8162306a36Sopenharmony_ci			       struct apparmor_audit_data *ad)
8262306a36Sopenharmony_ci{
8362306a36Sopenharmony_ci	struct aa_ruleset *rules = list_first_entry(&profile->rules,
8462306a36Sopenharmony_ci						    typeof(*rules), list);
8562306a36Sopenharmony_ci	struct aa_perms perms;
8662306a36Sopenharmony_ci	aa_state_t state;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (profile_unconfined(profile) ||
8962306a36Sopenharmony_ci	    !ANY_RULE_MEDIATES(&profile->rules, AA_CLASS_SIGNAL))
9062306a36Sopenharmony_ci		return 0;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	ad->subj_cred = cred;
9362306a36Sopenharmony_ci	ad->peer = peer;
9462306a36Sopenharmony_ci	/* TODO: secondary cache check <profile, profile, perm> */
9562306a36Sopenharmony_ci	state = aa_dfa_next(rules->policy.dfa,
9662306a36Sopenharmony_ci			    rules->policy.start[AA_CLASS_SIGNAL],
9762306a36Sopenharmony_ci			    ad->signal);
9862306a36Sopenharmony_ci	aa_label_match(profile, rules, peer, state, false, request, &perms);
9962306a36Sopenharmony_ci	aa_apply_modes_to_perms(profile, &perms);
10062306a36Sopenharmony_ci	return aa_check_perms(profile, &perms, request, ad, audit_signal_cb);
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ciint aa_may_signal(const struct cred *subj_cred, struct aa_label *sender,
10462306a36Sopenharmony_ci		  const struct cred *target_cred, struct aa_label *target,
10562306a36Sopenharmony_ci		  int sig)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	struct aa_profile *profile;
10862306a36Sopenharmony_ci	DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_SIGNAL, OP_SIGNAL);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	ad.signal = map_signal_num(sig);
11162306a36Sopenharmony_ci	ad.unmappedsig = sig;
11262306a36Sopenharmony_ci	return xcheck_labels(sender, target, profile,
11362306a36Sopenharmony_ci			     profile_signal_perm(subj_cred, profile, target,
11462306a36Sopenharmony_ci						 MAY_WRITE, &ad),
11562306a36Sopenharmony_ci			     profile_signal_perm(target_cred, profile, sender,
11662306a36Sopenharmony_ci						 MAY_READ, &ad));
11762306a36Sopenharmony_ci}
118