]>
Commit | Line | Data |
---|---|---|
0ed3b28a JJ |
1 | /* |
2 | * AppArmor security module | |
3 | * | |
4 | * This file contains AppArmor ipc mediation | |
5 | * | |
6 | * Copyright (C) 1998-2008 Novell/SUSE | |
b2d09ae4 | 7 | * Copyright 2009-2017 Canonical Ltd. |
0ed3b28a JJ |
8 | * |
9 | * This program is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU General Public License as | |
11 | * published by the Free Software Foundation, version 2 of the | |
12 | * License. | |
13 | */ | |
14 | ||
15 | #include <linux/gfp.h> | |
16 | #include <linux/ptrace.h> | |
17 | ||
18 | #include "include/audit.h" | |
19 | #include "include/capability.h" | |
20 | #include "include/context.h" | |
21 | #include "include/policy.h" | |
33f8bf58 | 22 | #include "include/ipc.h" |
cd1dbf76 | 23 | #include "include/sig_names.h" |
0ed3b28a | 24 | |
290f458a JJ |
25 | /** |
26 | * audit_ptrace_mask - convert mask to permission string | |
27 | * @buffer: buffer to write string to (NOT NULL) | |
28 | * @mask: permission mask to convert | |
29 | */ | |
30 | static void audit_ptrace_mask(struct audit_buffer *ab, u32 mask) | |
31 | { | |
32 | switch (mask) { | |
33 | case MAY_READ: | |
34 | audit_log_string(ab, "read"); | |
35 | break; | |
36 | case MAY_WRITE: | |
37 | audit_log_string(ab, "trace"); | |
38 | break; | |
39 | case AA_MAY_BE_READ: | |
40 | audit_log_string(ab, "readby"); | |
41 | break; | |
42 | case AA_MAY_BE_TRACED: | |
43 | audit_log_string(ab, "tracedby"); | |
44 | break; | |
45 | } | |
46 | } | |
47 | ||
0ed3b28a | 48 | /* call back to audit ptrace fields */ |
637f688d | 49 | static void audit_ptrace_cb(struct audit_buffer *ab, void *va) |
0ed3b28a JJ |
50 | { |
51 | struct common_audit_data *sa = va; | |
b2d09ae4 | 52 | |
290f458a JJ |
53 | if (aad(sa)->request & AA_PTRACE_PERM_MASK) { |
54 | audit_log_format(ab, " requested_mask="); | |
55 | audit_ptrace_mask(ab, aad(sa)->request); | |
56 | ||
57 | if (aad(sa)->denied & AA_PTRACE_PERM_MASK) { | |
58 | audit_log_format(ab, " denied_mask="); | |
59 | audit_ptrace_mask(ab, aad(sa)->denied); | |
60 | } | |
61 | } | |
ef88a7ac | 62 | audit_log_format(ab, " peer="); |
637f688d JJ |
63 | aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, |
64 | FLAGS_NONE, GFP_ATOMIC); | |
0ed3b28a JJ |
65 | } |
66 | ||
290f458a JJ |
67 | /* TODO: conditionals */ |
68 | static int profile_ptrace_perm(struct aa_profile *profile, | |
69 | struct aa_profile *peer, u32 request, | |
70 | struct common_audit_data *sa) | |
71 | { | |
72 | struct aa_perms perms = { }; | |
73 | ||
74 | /* need because of peer in cross check */ | |
75 | if (profile_unconfined(profile) || | |
76 | !PROFILE_MEDIATES(profile, AA_CLASS_PTRACE)) | |
77 | return 0; | |
78 | ||
79 | aad(sa)->peer = &peer->label; | |
80 | aa_profile_match_label(profile, &peer->label, AA_CLASS_PTRACE, request, | |
81 | &perms); | |
82 | aa_apply_modes_to_perms(profile, &perms); | |
83 | return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); | |
84 | } | |
85 | ||
b2d09ae4 JJ |
86 | static int cross_ptrace_perm(struct aa_profile *tracer, |
87 | struct aa_profile *tracee, u32 request, | |
88 | struct common_audit_data *sa) | |
0ed3b28a | 89 | { |
290f458a JJ |
90 | if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) |
91 | return xcheck(profile_ptrace_perm(tracer, tracee, request, sa), | |
92 | profile_ptrace_perm(tracee, tracer, | |
93 | request << PTRACE_PERM_SHIFT, | |
94 | sa)); | |
b2d09ae4 JJ |
95 | /* policy uses the old style capability check for ptrace */ |
96 | if (profile_unconfined(tracer) || tracer == tracee) | |
97 | return 0; | |
0ed3b28a | 98 | |
b2d09ae4 JJ |
99 | aad(sa)->label = &tracer->label; |
100 | aad(sa)->peer = &tracee->label; | |
101 | aad(sa)->request = 0; | |
102 | aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1); | |
ef88a7ac | 103 | |
b2d09ae4 | 104 | return aa_audit(AUDIT_APPARMOR_AUTO, tracer, sa, audit_ptrace_cb); |
0ed3b28a JJ |
105 | } |
106 | ||
107 | /** | |
108 | * aa_may_ptrace - test if tracer task can trace the tracee | |
b2d09ae4 JJ |
109 | * @tracer: label of the task doing the tracing (NOT NULL) |
110 | * @tracee: task label to be traced | |
111 | * @request: permission request | |
0ed3b28a JJ |
112 | * |
113 | * Returns: %0 else error code if permission denied or error | |
114 | */ | |
b2d09ae4 JJ |
115 | int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, |
116 | u32 request) | |
0ed3b28a | 117 | { |
b2d09ae4 | 118 | DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); |
0ed3b28a | 119 | |
b2d09ae4 JJ |
120 | return xcheck_labels_profiles(tracer, tracee, cross_ptrace_perm, |
121 | request, &sa); | |
0ed3b28a JJ |
122 | } |
123 | ||
0ed3b28a | 124 | |
cd1dbf76 JJ |
125 | static inline int map_signal_num(int sig) |
126 | { | |
127 | if (sig > SIGRTMAX) | |
128 | return SIGUNKNOWN; | |
129 | else if (sig >= SIGRTMIN) | |
130 | return sig - SIGRTMIN + 128; /* rt sigs mapped to 128 */ | |
131 | else if (sig <= MAXMAPPED_SIG) | |
132 | return sig_map[sig]; | |
133 | return SIGUNKNOWN; | |
134 | } | |
135 | ||
136 | /** | |
137 | * audit_file_mask - convert mask to permission string | |
138 | * @buffer: buffer to write string to (NOT NULL) | |
139 | * @mask: permission mask to convert | |
140 | */ | |
141 | static void audit_signal_mask(struct audit_buffer *ab, u32 mask) | |
142 | { | |
143 | if (mask & MAY_READ) | |
144 | audit_log_string(ab, "receive"); | |
145 | if (mask & MAY_WRITE) | |
146 | audit_log_string(ab, "send"); | |
147 | } | |
148 | ||
149 | /** | |
150 | * audit_cb - call back for signal specific audit fields | |
151 | * @ab: audit_buffer (NOT NULL) | |
152 | * @va: audit struct to audit values of (NOT NULL) | |
153 | */ | |
154 | static void audit_signal_cb(struct audit_buffer *ab, void *va) | |
155 | { | |
156 | struct common_audit_data *sa = va; | |
157 | ||
158 | if (aad(sa)->request & AA_SIGNAL_PERM_MASK) { | |
159 | audit_log_format(ab, " requested_mask="); | |
160 | audit_signal_mask(ab, aad(sa)->request); | |
161 | if (aad(sa)->denied & AA_SIGNAL_PERM_MASK) { | |
162 | audit_log_format(ab, " denied_mask="); | |
163 | audit_signal_mask(ab, aad(sa)->denied); | |
164 | } | |
165 | } | |
166 | if (aad(sa)->signal <= MAXMAPPED_SIG) | |
167 | audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]); | |
168 | else | |
169 | audit_log_format(ab, " signal=rtmin+%d", | |
170 | aad(sa)->signal - 128); | |
171 | audit_log_format(ab, " peer="); | |
172 | aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, | |
173 | FLAGS_NONE, GFP_ATOMIC); | |
174 | } | |
175 | ||
176 | /* TODO: update to handle compound name&name2, conditionals */ | |
177 | static void profile_match_signal(struct aa_profile *profile, const char *label, | |
178 | int signal, struct aa_perms *perms) | |
179 | { | |
180 | unsigned int state; | |
181 | ||
182 | /* TODO: secondary cache check <profile, profile, perm> */ | |
183 | state = aa_dfa_next(profile->policy.dfa, | |
184 | profile->policy.start[AA_CLASS_SIGNAL], | |
185 | signal); | |
186 | state = aa_dfa_match(profile->policy.dfa, state, label); | |
187 | aa_compute_perms(profile->policy.dfa, state, perms); | |
188 | } | |
189 | ||
190 | static int profile_signal_perm(struct aa_profile *profile, | |
191 | struct aa_profile *peer, u32 request, | |
192 | struct common_audit_data *sa) | |
193 | { | |
194 | struct aa_perms perms; | |
195 | ||
196 | if (profile_unconfined(profile) || | |
197 | !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL)) | |
198 | return 0; | |
199 | ||
200 | aad(sa)->peer = &peer->label; | |
201 | profile_match_signal(profile, peer->base.hname, aad(sa)->signal, | |
202 | &perms); | |
203 | aa_apply_modes_to_perms(profile, &perms); | |
204 | return aa_check_perms(profile, &perms, request, sa, audit_signal_cb); | |
205 | } | |
206 | ||
207 | static int aa_signal_cross_perm(struct aa_profile *sender, | |
208 | struct aa_profile *target, | |
209 | struct common_audit_data *sa) | |
210 | { | |
211 | return xcheck(profile_signal_perm(sender, target, MAY_WRITE, sa), | |
212 | profile_signal_perm(target, sender, MAY_READ, sa)); | |
213 | } | |
214 | ||
215 | int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig) | |
216 | { | |
217 | DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SIGNAL); | |
218 | ||
219 | aad(&sa)->signal = map_signal_num(sig); | |
220 | return xcheck_labels_profiles(sender, target, aa_signal_cross_perm, | |
221 | &sa); | |
222 | } |