]> git.pld-linux.org Git - packages/kernel.git/blame - 0006-apparmor-add-the-ability-to-mediate-signals.patch
- drop obsolete files
[packages/kernel.git] / 0006-apparmor-add-the-ability-to-mediate-signals.patch
CommitLineData
daaa955e
AM
1From f9e20353a6c5726775867db81b6085e8ab425a36 Mon Sep 17 00:00:00 2001
2From: John Johansen <john.johansen@canonical.com>
3Date: Tue, 18 Jul 2017 22:56:22 -0700
4Subject: [PATCH 06/17] apparmor: add the ability to mediate signals
5
6Add signal mediation where the signal can be mediated based on the
7signal, direction, or the label or the peer/target. The signal perms
8are verified on a cross check to ensure policy consistency in the case
9of incremental policy load/replacement.
10
11The optimization of skipping the cross check when policy is guaranteed
12to be consistent (single compile unit) remains to be done.
13
14policy rules have the form of
15 SIGNAL_RULE = [ QUALIFIERS ] 'signal' [ SIGNAL ACCESS PERMISSIONS ]
16 [ SIGNAL SET ] [ SIGNAL PEER ]
17
18 SIGNAL ACCESS PERMISSIONS = SIGNAL ACCESS | SIGNAL ACCESS LIST
19
20 SIGNAL ACCESS LIST = '(' Comma or space separated list of SIGNAL
21 ACCESS ')'
22
23 SIGNAL ACCESS = ( 'r' | 'w' | 'rw' | 'read' | 'write' | 'send' |
24 'receive' )
25
26 SIGNAL SET = 'set' '=' '(' SIGNAL LIST ')'
27
28 SIGNAL LIST = Comma or space separated list of SIGNALS
29
30 SIGNALS = ( 'hup' | 'int' | 'quit' | 'ill' | 'trap' | 'abrt' |
31 'bus' | 'fpe' | 'kill' | 'usr1' | 'segv' | 'usr2' |
32 'pipe' | 'alrm' | 'term' | 'stkflt' | 'chld' | 'cont' |
33 'stop' | 'stp' | 'ttin' | 'ttou' | 'urg' | 'xcpu' |
34 'xfsz' | 'vtalrm' | 'prof' | 'winch' | 'io' | 'pwr' |
35 'sys' | 'emt' | 'exists' | 'rtmin+0' ... 'rtmin+32'
36 )
37
38 SIGNAL PEER = 'peer' '=' AARE
39
40eg.
41 signal, # allow all signals
42 signal send set=(hup, kill) peer=foo,
43
44Signed-off-by: John Johansen <john.johansen@canonical.com>
45Acked-by: Seth Arnold <seth.arnold@canonical.com>
46(cherry picked from commit c6bf1adaecaa719d7c56338cc43b2982214f2f44)
47---
48 security/apparmor/apparmorfs.c | 7 +++
49 security/apparmor/include/apparmor.h | 1 +
50 security/apparmor/include/audit.h | 2 +
51 security/apparmor/include/ipc.h | 6 +++
52 security/apparmor/include/sig_names.h | 95 +++++++++++++++++++++++++++++++++
53 security/apparmor/ipc.c | 99 +++++++++++++++++++++++++++++++++++
54 security/apparmor/lsm.c | 21 ++++++++
55 7 files changed, 231 insertions(+)
56 create mode 100644 security/apparmor/include/sig_names.h
57
58diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
59index 2caeb748070c..a5f9e1aa51f7 100644
60--- a/security/apparmor/apparmorfs.c
61+++ b/security/apparmor/apparmorfs.c
62@@ -32,6 +32,7 @@
63 #include "include/audit.h"
64 #include "include/context.h"
65 #include "include/crypto.h"
66+#include "include/ipc.h"
67 #include "include/policy_ns.h"
68 #include "include/label.h"
69 #include "include/policy.h"
70@@ -2129,6 +2130,11 @@ static struct aa_sfs_entry aa_sfs_entry_ptrace[] = {
71 { }
72 };
73
74+static struct aa_sfs_entry aa_sfs_entry_signal[] = {
75+ AA_SFS_FILE_STRING("mask", AA_SFS_SIG_MASK),
76+ { }
77+};
78+
79 static struct aa_sfs_entry aa_sfs_entry_domain[] = {
80 AA_SFS_FILE_BOOLEAN("change_hat", 1),
81 AA_SFS_FILE_BOOLEAN("change_hatv", 1),
82@@ -2179,6 +2185,7 @@ static struct aa_sfs_entry aa_sfs_entry_features[] = {
83 AA_SFS_DIR("rlimit", aa_sfs_entry_rlimit),
84 AA_SFS_DIR("caps", aa_sfs_entry_caps),
85 AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace),
86+ AA_SFS_DIR("signal", aa_sfs_entry_signal),
87 AA_SFS_DIR("query", aa_sfs_entry_query),
88 { }
89 };
90diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
91index aaf893f4e4f5..962a20a75e01 100644
92--- a/security/apparmor/include/apparmor.h
93+++ b/security/apparmor/include/apparmor.h
94@@ -28,6 +28,7 @@
95 #define AA_CLASS_RLIMITS 5
96 #define AA_CLASS_DOMAIN 6
97 #define AA_CLASS_PTRACE 9
98+#define AA_CLASS_SIGNAL 10
99 #define AA_CLASS_LABEL 16
100
101 #define AA_CLASS_LAST AA_CLASS_LABEL
102diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
103index c68839a44351..d9a156ae11b9 100644
104--- a/security/apparmor/include/audit.h
105+++ b/security/apparmor/include/audit.h
106@@ -86,6 +86,7 @@ enum audit_type {
107 #define OP_SHUTDOWN "socket_shutdown"
108
109 #define OP_PTRACE "ptrace"
110+#define OP_SIGNAL "signal"
111
112 #define OP_EXEC "exec"
113
114@@ -126,6 +127,7 @@ struct apparmor_audit_data {
115 long pos;
116 const char *ns;
117 } iface;
118+ int signal;
119 struct {
120 int rlim;
121 unsigned long max;
122diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h
123index 656fdb81c8a0..5ffc218d1e74 100644
124--- a/security/apparmor/include/ipc.h
125+++ b/security/apparmor/include/ipc.h
126@@ -27,8 +27,14 @@ struct aa_profile;
127
128 #define AA_PTRACE_PERM_MASK (AA_PTRACE_READ | AA_PTRACE_TRACE | \
129 AA_MAY_BE_READ | AA_MAY_BE_TRACED)
130+#define AA_SIGNAL_PERM_MASK (MAY_READ | MAY_WRITE)
131+
132+#define AA_SFS_SIG_MASK "hup int quit ill trap abrt bus fpe kill usr1 " \
133+ "segv usr2 pipe alrm term stkflt chld cont stop stp ttin ttou urg " \
134+ "xcpu xfsz vtalrm prof winch io pwr sys emt lost"
135
136 int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
137 u32 request);
138+int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig);
139
140 #endif /* __AA_IPC_H */
141diff --git a/security/apparmor/include/sig_names.h b/security/apparmor/include/sig_names.h
142new file mode 100644
143index 000000000000..0d4395f231ca
144--- /dev/null
145+++ b/security/apparmor/include/sig_names.h
146@@ -0,0 +1,95 @@
147+#include <linux/signal.h>
148+
149+#define SIGUNKNOWN 0
150+#define MAXMAPPED_SIG 35
151+/* provide a mapping of arch signal to internal signal # for mediation
152+ * those that are always an alias SIGCLD for SIGCLHD and SIGPOLL for SIGIO
153+ * map to the same entry those that may/or may not get a separate entry
154+ */
155+static const int sig_map[MAXMAPPED_SIG] = {
156+ [0] = MAXMAPPED_SIG, /* existence test */
157+ [SIGHUP] = 1,
158+ [SIGINT] = 2,
159+ [SIGQUIT] = 3,
160+ [SIGILL] = 4,
161+ [SIGTRAP] = 5, /* -, 5, - */
162+ [SIGABRT] = 6, /* SIGIOT: -, 6, - */
163+ [SIGBUS] = 7, /* 10, 7, 10 */
164+ [SIGFPE] = 8,
165+ [SIGKILL] = 9,
166+ [SIGUSR1] = 10, /* 30, 10, 16 */
167+ [SIGSEGV] = 11,
168+ [SIGUSR2] = 12, /* 31, 12, 17 */
169+ [SIGPIPE] = 13,
170+ [SIGALRM] = 14,
171+ [SIGTERM] = 15,
172+ [SIGSTKFLT] = 16, /* -, 16, - */
173+ [SIGCHLD] = 17, /* 20, 17, 18. SIGCHLD -, -, 18 */
174+ [SIGCONT] = 18, /* 19, 18, 25 */
175+ [SIGSTOP] = 19, /* 17, 19, 23 */
176+ [SIGTSTP] = 20, /* 18, 20, 24 */
177+ [SIGTTIN] = 21, /* 21, 21, 26 */
178+ [SIGTTOU] = 22, /* 22, 22, 27 */
179+ [SIGURG] = 23, /* 16, 23, 21 */
180+ [SIGXCPU] = 24, /* 24, 24, 30 */
181+ [SIGXFSZ] = 25, /* 25, 25, 31 */
182+ [SIGVTALRM] = 26, /* 26, 26, 28 */
183+ [SIGPROF] = 27, /* 27, 27, 29 */
184+ [SIGWINCH] = 28, /* 28, 28, 20 */
185+ [SIGIO] = 29, /* SIGPOLL: 23, 29, 22 */
186+ [SIGPWR] = 30, /* 29, 30, 19. SIGINFO 29, -, - */
187+#ifdef SIGSYS
188+ [SIGSYS] = 31, /* 12, 31, 12. often SIG LOST/UNUSED */
189+#endif
190+#ifdef SIGEMT
191+ [SIGEMT] = 32, /* 7, - , 7 */
192+#endif
193+#if defined(SIGLOST) && SIGPWR != SIGLOST /* sparc */
194+ [SIGLOST] = 33, /* unused on Linux */
195+#endif
196+#if defined(SIGLOST) && defined(SIGSYS) && SIGLOST != SIGSYS
197+ [SIGUNUSED] = 34, /* -, 31, - */
198+#endif
199+};
200+
201+/* this table is ordered post sig_map[sig] mapping */
202+static const char *const sig_names[MAXMAPPED_SIG + 1] = {
203+ "unknown",
204+ "hup",
205+ "int",
206+ "quit",
207+ "ill",
208+ "trap",
209+ "abrt",
210+ "bus",
211+ "fpe",
212+ "kill",
213+ "usr1",
214+ "segv",
215+ "usr2",
216+ "pipe",
217+ "alrm",
218+ "term",
219+ "stkflt",
220+ "chld",
221+ "cont",
222+ "stop",
223+ "stp",
224+ "ttin",
225+ "ttou",
226+ "urg",
227+ "xcpu",
228+ "xfsz",
229+ "vtalrm",
230+ "prof",
231+ "winch",
232+ "io",
233+ "pwr",
234+ "sys",
235+ "emt",
236+ "lost",
237+ "unused",
238+
239+ "exists", /* always last existence test mapped to MAXMAPPED_SIG */
240+};
241+
242diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
243index 11e66b5bbc42..66fb9ede9447 100644
244--- a/security/apparmor/ipc.c
245+++ b/security/apparmor/ipc.c
246@@ -20,6 +20,7 @@
247 #include "include/context.h"
248 #include "include/policy.h"
249 #include "include/ipc.h"
250+#include "include/sig_names.h"
251
252 /**
253 * audit_ptrace_mask - convert mask to permission string
254@@ -121,3 +122,101 @@ int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee,
255 }
256
257
258+static inline int map_signal_num(int sig)
259+{
260+ if (sig > SIGRTMAX)
261+ return SIGUNKNOWN;
262+ else if (sig >= SIGRTMIN)
263+ return sig - SIGRTMIN + 128; /* rt sigs mapped to 128 */
264+ else if (sig <= MAXMAPPED_SIG)
265+ return sig_map[sig];
266+ return SIGUNKNOWN;
267+}
268+
269+/**
270+ * audit_file_mask - convert mask to permission string
271+ * @buffer: buffer to write string to (NOT NULL)
272+ * @mask: permission mask to convert
273+ */
274+static void audit_signal_mask(struct audit_buffer *ab, u32 mask)
275+{
276+ if (mask & MAY_READ)
277+ audit_log_string(ab, "receive");
278+ if (mask & MAY_WRITE)
279+ audit_log_string(ab, "send");
280+}
281+
282+/**
283+ * audit_cb - call back for signal specific audit fields
284+ * @ab: audit_buffer (NOT NULL)
285+ * @va: audit struct to audit values of (NOT NULL)
286+ */
287+static void audit_signal_cb(struct audit_buffer *ab, void *va)
288+{
289+ struct common_audit_data *sa = va;
290+
291+ if (aad(sa)->request & AA_SIGNAL_PERM_MASK) {
292+ audit_log_format(ab, " requested_mask=");
293+ audit_signal_mask(ab, aad(sa)->request);
294+ if (aad(sa)->denied & AA_SIGNAL_PERM_MASK) {
295+ audit_log_format(ab, " denied_mask=");
296+ audit_signal_mask(ab, aad(sa)->denied);
297+ }
298+ }
299+ if (aad(sa)->signal <= MAXMAPPED_SIG)
300+ audit_log_format(ab, " signal=%s", sig_names[aad(sa)->signal]);
301+ else
302+ audit_log_format(ab, " signal=rtmin+%d",
303+ aad(sa)->signal - 128);
304+ audit_log_format(ab, " peer=");
305+ aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer,
306+ FLAGS_NONE, GFP_ATOMIC);
307+}
308+
309+/* TODO: update to handle compound name&name2, conditionals */
310+static void profile_match_signal(struct aa_profile *profile, const char *label,
311+ int signal, struct aa_perms *perms)
312+{
313+ unsigned int state;
314+
315+ /* TODO: secondary cache check <profile, profile, perm> */
316+ state = aa_dfa_next(profile->policy.dfa,
317+ profile->policy.start[AA_CLASS_SIGNAL],
318+ signal);
319+ state = aa_dfa_match(profile->policy.dfa, state, label);
320+ aa_compute_perms(profile->policy.dfa, state, perms);
321+}
322+
323+static int profile_signal_perm(struct aa_profile *profile,
324+ struct aa_profile *peer, u32 request,
325+ struct common_audit_data *sa)
326+{
327+ struct aa_perms perms;
328+
329+ if (profile_unconfined(profile) ||
330+ !PROFILE_MEDIATES(profile, AA_CLASS_SIGNAL))
331+ return 0;
332+
333+ aad(sa)->peer = &peer->label;
334+ profile_match_signal(profile, peer->base.hname, aad(sa)->signal,
335+ &perms);
336+ aa_apply_modes_to_perms(profile, &perms);
337+ return aa_check_perms(profile, &perms, request, sa, audit_signal_cb);
338+}
339+
340+static int aa_signal_cross_perm(struct aa_profile *sender,
341+ struct aa_profile *target,
342+ struct common_audit_data *sa)
343+{
344+ return xcheck(profile_signal_perm(sender, target, MAY_WRITE, sa),
345+ profile_signal_perm(target, sender, MAY_READ, sa));
346+}
347+
348+int aa_may_signal(struct aa_label *sender, struct aa_label *target, int sig)
349+{
350+ DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SIGNAL);
351+
352+ aad(&sa)->signal = map_signal_num(sig);
353+ return xcheck_labels_profiles(sender, target, aa_signal_cross_perm,
354+ &sa);
355+}
356diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
357index 867bcd154c7e..af22f3dfbcce 100644
358--- a/security/apparmor/lsm.c
359+++ b/security/apparmor/lsm.c
360@@ -656,6 +656,26 @@ static int apparmor_task_setrlimit(struct task_struct *task,
361 return error;
362 }
363
364+static int apparmor_task_kill(struct task_struct *target, struct siginfo *info,
365+ int sig, u32 secid)
366+{
367+ struct aa_label *cl, *tl;
368+ int error;
369+
370+ if (secid)
371+ /* TODO: after secid to label mapping is done.
372+ * Dealing with USB IO specific behavior
373+ */
374+ return 0;
375+ cl = __begin_current_label_crit_section();
376+ tl = aa_get_task_label(target);
377+ error = aa_may_signal(cl, tl, sig);
378+ aa_put_label(tl);
379+ __end_current_label_crit_section(cl);
380+
381+ return error;
382+}
383+
384 static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
385 LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
386 LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
387@@ -697,6 +717,7 @@ static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
388 LSM_HOOK_INIT(bprm_secureexec, apparmor_bprm_secureexec),
389
390 LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
391+ LSM_HOOK_INIT(task_kill, apparmor_task_kill),
392 };
393
394 /*
395--
3962.11.0
397
This page took 0.085597 seconds and 4 git commands to generate.