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