]> git.pld-linux.org Git - packages/kernel.git/blob - 0006-apparmor-add-the-ability-to-mediate-signals.patch
- up to 4.13.7; fixes CVE-2017-5123
[packages/kernel.git] / 0006-apparmor-add-the-ability-to-mediate-signals.patch
1 From f9e20353a6c5726775867db81b6085e8ab425a36 Mon Sep 17 00:00:00 2001
2 From: John Johansen <john.johansen@canonical.com>
3 Date: Tue, 18 Jul 2017 22:56:22 -0700
4 Subject: [PATCH 06/17] apparmor: add the ability to mediate signals
5
6 Add signal mediation where the signal can be mediated based on the
7 signal, direction, or the label or the peer/target. The signal perms
8 are verified on a cross check to ensure policy consistency in the case
9 of incremental policy load/replacement.
10
11 The optimization of skipping the cross check when policy is guaranteed
12 to be consistent (single compile unit) remains to be done.
13
14 policy 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
40 eg.
41   signal,                                 # allow all signals
42   signal send set=(hup, kill) peer=foo,
43
44 Signed-off-by: John Johansen <john.johansen@canonical.com>
45 Acked-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
58 diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
59 index 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  };
90 diff --git a/security/apparmor/include/apparmor.h b/security/apparmor/include/apparmor.h
91 index 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
102 diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h
103 index 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;
122 diff --git a/security/apparmor/include/ipc.h b/security/apparmor/include/ipc.h
123 index 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 */
141 diff --git a/security/apparmor/include/sig_names.h b/security/apparmor/include/sig_names.h
142 new file mode 100644
143 index 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 +
242 diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c
243 index 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 +}
356 diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c
357 index 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 -- 
396 2.11.0
397
This page took 0.075739 seconds and 3 git commands to generate.