diff options
Diffstat (limited to 'security/apparmor/ipc.c')
-rw-r--r-- | security/apparmor/ipc.c | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index 11e66b5bbc42..66fb9ede9447 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "include/context.h" | 20 | #include "include/context.h" |
21 | #include "include/policy.h" | 21 | #include "include/policy.h" |
22 | #include "include/ipc.h" | 22 | #include "include/ipc.h" |
23 | #include "include/sig_names.h" | ||
23 | 24 | ||
24 | /** | 25 | /** |
25 | * audit_ptrace_mask - convert mask to permission string | 26 | * audit_ptrace_mask - convert mask to permission string |
@@ -121,3 +122,101 @@ int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, | |||
121 | } | 122 | } |
122 | 123 | ||
123 | 124 | ||
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 | } | ||