1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * AppArmor security module |
4 | * |
5 | * This file contains AppArmor ipc mediation |
6 | * |
7 | * Copyright (C) 1998-2008 Novell/SUSE |
8 | * Copyright 2009-2017 Canonical Ltd. |
9 | */ |
10 | |
11 | #include <linux/gfp.h> |
12 | |
13 | #include "include/audit.h" |
14 | #include "include/capability.h" |
15 | #include "include/cred.h" |
16 | #include "include/policy.h" |
17 | #include "include/ipc.h" |
18 | #include "include/sig_names.h" |
19 | |
20 | |
21 | static inline int map_signal_num(int sig) |
22 | { |
23 | if (sig > SIGRTMAX) |
24 | return SIGUNKNOWN; |
25 | else if (sig >= SIGRTMIN) |
26 | return sig - SIGRTMIN + SIGRT_BASE; |
27 | else if (sig < MAXMAPPED_SIG) |
28 | return sig_map[sig]; |
29 | return SIGUNKNOWN; |
30 | } |
31 | |
32 | /** |
33 | * audit_signal_mask - convert mask to permission string |
34 | * @mask: permission mask to convert |
35 | * |
36 | * Returns: pointer to static string |
37 | */ |
38 | static const char *audit_signal_mask(u32 mask) |
39 | { |
40 | if (mask & MAY_READ) |
41 | return "receive" ; |
42 | if (mask & MAY_WRITE) |
43 | return "send" ; |
44 | return "" ; |
45 | } |
46 | |
47 | /** |
48 | * audit_signal_cb() - call back for signal specific audit fields |
49 | * @ab: audit_buffer (NOT NULL) |
50 | * @va: audit struct to audit values of (NOT NULL) |
51 | */ |
52 | static void audit_signal_cb(struct audit_buffer *ab, void *va) |
53 | { |
54 | struct common_audit_data *sa = va; |
55 | struct apparmor_audit_data *ad = aad(sa); |
56 | |
57 | if (ad->request & AA_SIGNAL_PERM_MASK) { |
58 | audit_log_format(ab, fmt: " requested_mask=\"%s\"" , |
59 | audit_signal_mask(mask: ad->request)); |
60 | if (ad->denied & AA_SIGNAL_PERM_MASK) { |
61 | audit_log_format(ab, fmt: " denied_mask=\"%s\"" , |
62 | audit_signal_mask(mask: ad->denied)); |
63 | } |
64 | } |
65 | if (ad->signal == SIGUNKNOWN) |
66 | audit_log_format(ab, fmt: "signal=unknown(%d)" , |
67 | ad->unmappedsig); |
68 | else if (ad->signal < MAXMAPPED_SIGNAME) |
69 | audit_log_format(ab, fmt: " signal=%s" , sig_names[ad->signal]); |
70 | else |
71 | audit_log_format(ab, fmt: " signal=rtmin+%d" , |
72 | ad->signal - SIGRT_BASE); |
73 | audit_log_format(ab, fmt: " peer=" ); |
74 | aa_label_xaudit(ab, labels_ns(ad->subj_label), label: ad->peer, |
75 | FLAGS_NONE, GFP_ATOMIC); |
76 | } |
77 | |
78 | static int profile_signal_perm(const struct cred *cred, |
79 | struct aa_profile *profile, |
80 | struct aa_label *peer, u32 request, |
81 | struct apparmor_audit_data *ad) |
82 | { |
83 | struct aa_ruleset *rules = list_first_entry(&profile->rules, |
84 | typeof(*rules), list); |
85 | struct aa_perms perms; |
86 | aa_state_t state; |
87 | |
88 | if (profile_unconfined(profile) || |
89 | !ANY_RULE_MEDIATES(head: &profile->rules, AA_CLASS_SIGNAL)) |
90 | return 0; |
91 | |
92 | ad->subj_cred = cred; |
93 | ad->peer = peer; |
94 | /* TODO: secondary cache check <profile, profile, perm> */ |
95 | state = aa_dfa_next(dfa: rules->policy->dfa, |
96 | state: rules->policy->start[AA_CLASS_SIGNAL], |
97 | c: ad->signal); |
98 | aa_label_match(profile, rules, label: peer, state, subns: false, request, perms: &perms); |
99 | aa_apply_modes_to_perms(profile, perms: &perms); |
100 | return aa_check_perms(profile, perms: &perms, request, ad, cb: audit_signal_cb); |
101 | } |
102 | |
103 | int aa_may_signal(const struct cred *subj_cred, struct aa_label *sender, |
104 | const struct cred *target_cred, struct aa_label *target, |
105 | int sig) |
106 | { |
107 | struct aa_profile *profile; |
108 | DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_SIGNAL, OP_SIGNAL); |
109 | |
110 | ad.signal = map_signal_num(sig); |
111 | ad.unmappedsig = sig; |
112 | return xcheck_labels(sender, target, profile, |
113 | profile_signal_perm(subj_cred, profile, target, |
114 | MAY_WRITE, &ad), |
115 | profile_signal_perm(target_cred, profile, sender, |
116 | MAY_READ, &ad)); |
117 | } |
118 | |