Commit 55669bfa141b488be865341ed12e188967d11308
1 parent
dc104fb323
Exists in
master
and in
4 other branches
[PATCH] audit: AUDIT_PERM support
add support for AUDIT_PERM predicate Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Showing 13 changed files with 236 additions and 0 deletions Side-by-side Diff
- arch/i386/kernel/audit.c
- arch/ia64/ia32/audit.c
- arch/ia64/kernel/audit.c
- arch/powerpc/kernel/audit.c
- arch/powerpc/kernel/compat_audit.c
- arch/s390/kernel/audit.c
- arch/s390/kernel/compat_audit.c
- arch/x86_64/ia32/audit.c
- arch/x86_64/kernel/audit.c
- include/linux/audit.h
- kernel/audit.h
- kernel/auditfilter.c
- kernel/auditsc.c
arch/i386/kernel/audit.c
... | ... | @@ -23,6 +23,22 @@ |
23 | 23 | ~0U |
24 | 24 | }; |
25 | 25 | |
26 | +int audit_classify_syscall(int abi, unsigned syscall) | |
27 | +{ | |
28 | + switch(syscall) { | |
29 | + case __NR_open: | |
30 | + return 2; | |
31 | + case __NR_openat: | |
32 | + return 3; | |
33 | + case __NR_socketcall: | |
34 | + return 4; | |
35 | + case __NR_execve: | |
36 | + return 5; | |
37 | + default: | |
38 | + return 0; | |
39 | + } | |
40 | +} | |
41 | + | |
26 | 42 | static int __init audit_classes_init(void) |
27 | 43 | { |
28 | 44 | audit_register_class(AUDIT_CLASS_WRITE, write_class); |
arch/ia64/ia32/audit.c
... | ... | @@ -19,4 +19,20 @@ |
19 | 19 | #include <asm-generic/audit_read.h> |
20 | 20 | ~0U |
21 | 21 | }; |
22 | + | |
23 | +int ia32_classify_syscall(unsigned syscall) | |
24 | +{ | |
25 | + switch(syscall) { | |
26 | + case __NR_open: | |
27 | + return 2; | |
28 | + case __NR_openat: | |
29 | + return 3; | |
30 | + case __NR_socketcall: | |
31 | + return 4; | |
32 | + case __NR_execve: | |
33 | + return 5; | |
34 | + default: | |
35 | + return 1; | |
36 | + } | |
37 | +} |
arch/ia64/kernel/audit.c
... | ... | @@ -23,6 +23,25 @@ |
23 | 23 | ~0U |
24 | 24 | }; |
25 | 25 | |
26 | +int audit_classify_syscall(int abi, unsigned syscall) | |
27 | +{ | |
28 | +#ifdef CONFIG_IA32_SUPPORT | |
29 | + extern int ia32_classify_syscall(unsigned); | |
30 | + if (abi == AUDIT_ARCH_I386) | |
31 | + return ia32_classify_syscall(syscall); | |
32 | +#endif | |
33 | + switch(syscall) { | |
34 | + case __NR_open: | |
35 | + return 2; | |
36 | + case __NR_openat: | |
37 | + return 3; | |
38 | + case __NR_execve: | |
39 | + return 5; | |
40 | + default: | |
41 | + return 0; | |
42 | + } | |
43 | +} | |
44 | + | |
26 | 45 | static int __init audit_classes_init(void) |
27 | 46 | { |
28 | 47 | #ifdef CONFIG_IA32_SUPPORT |
arch/powerpc/kernel/audit.c
... | ... | @@ -23,6 +23,27 @@ |
23 | 23 | ~0U |
24 | 24 | }; |
25 | 25 | |
26 | +int audit_classify_syscall(int abi, unsigned syscall) | |
27 | +{ | |
28 | +#ifdef CONFIG_PPC64 | |
29 | + extern int ppc32_classify_syscall(unsigned); | |
30 | + if (abi == AUDIT_ARCH_PPC) | |
31 | + return ppc32_classify_syscall(syscall); | |
32 | +#endif | |
33 | + switch(syscall) { | |
34 | + case __NR_open: | |
35 | + return 2; | |
36 | + case __NR_openat: | |
37 | + return 3; | |
38 | + case __NR_socketcall: | |
39 | + return 4; | |
40 | + case __NR_execve: | |
41 | + return 5; | |
42 | + default: | |
43 | + return 0; | |
44 | + } | |
45 | +} | |
46 | + | |
26 | 47 | static int __init audit_classes_init(void) |
27 | 48 | { |
28 | 49 | #ifdef CONFIG_PPC64 |
arch/powerpc/kernel/compat_audit.c
... | ... | @@ -20,4 +20,20 @@ |
20 | 20 | #include <asm-generic/audit_read.h> |
21 | 21 | ~0U |
22 | 22 | }; |
23 | + | |
24 | +int ppc32_classify_syscall(unsigned syscall) | |
25 | +{ | |
26 | + switch(syscall) { | |
27 | + case __NR_open: | |
28 | + return 2; | |
29 | + case __NR_openat: | |
30 | + return 3; | |
31 | + case __NR_socketcall: | |
32 | + return 4; | |
33 | + case __NR_execve: | |
34 | + return 5; | |
35 | + default: | |
36 | + return 1; | |
37 | + } | |
38 | +} |
arch/s390/kernel/audit.c
... | ... | @@ -23,6 +23,27 @@ |
23 | 23 | ~0U |
24 | 24 | }; |
25 | 25 | |
26 | +int audit_classify_syscall(int abi, unsigned syscall) | |
27 | +{ | |
28 | +#ifdef CONFIG_COMPAT | |
29 | + extern int s390_classify_syscall(unsigned); | |
30 | + if (abi == AUDIT_ARCH_S390) | |
31 | + return s390_classify_syscall(syscall); | |
32 | +#endif | |
33 | + switch(syscall) { | |
34 | + case __NR_open: | |
35 | + return 2; | |
36 | + case __NR_openat: | |
37 | + return 3; | |
38 | + case __NR_socketcall: | |
39 | + return 4; | |
40 | + case __NR_execve: | |
41 | + return 5; | |
42 | + default: | |
43 | + return 0; | |
44 | + } | |
45 | +} | |
46 | + | |
26 | 47 | static int __init audit_classes_init(void) |
27 | 48 | { |
28 | 49 | #ifdef CONFIG_COMPAT |
arch/s390/kernel/compat_audit.c
... | ... | @@ -20,4 +20,20 @@ |
20 | 20 | #include <asm-generic/audit_read.h> |
21 | 21 | ~0U |
22 | 22 | }; |
23 | + | |
24 | +int s390_classify_syscall(unsigned syscall) | |
25 | +{ | |
26 | + switch(syscall) { | |
27 | + case __NR_open: | |
28 | + return 2; | |
29 | + case __NR_openat: | |
30 | + return 3; | |
31 | + case __NR_socketcall: | |
32 | + return 4; | |
33 | + case __NR_execve: | |
34 | + return 5; | |
35 | + default: | |
36 | + return 1; | |
37 | + } | |
38 | +} |
arch/x86_64/ia32/audit.c
... | ... | @@ -19,4 +19,20 @@ |
19 | 19 | #include <asm-generic/audit_read.h> |
20 | 20 | ~0U |
21 | 21 | }; |
22 | + | |
23 | +int ia32_classify_syscall(unsigned syscall) | |
24 | +{ | |
25 | + switch(syscall) { | |
26 | + case __NR_open: | |
27 | + return 2; | |
28 | + case __NR_openat: | |
29 | + return 3; | |
30 | + case __NR_socketcall: | |
31 | + return 4; | |
32 | + case __NR_execve: | |
33 | + return 5; | |
34 | + default: | |
35 | + return 1; | |
36 | + } | |
37 | +} |
arch/x86_64/kernel/audit.c
... | ... | @@ -23,6 +23,25 @@ |
23 | 23 | ~0U |
24 | 24 | }; |
25 | 25 | |
26 | +int audit_classify_syscall(int abi, unsigned syscall) | |
27 | +{ | |
28 | +#ifdef CONFIG_IA32_EMULATION | |
29 | + extern int ia32_classify_syscall(unsigned); | |
30 | + if (abi == AUDIT_ARCH_I386) | |
31 | + return ia32_classify_syscall(syscall); | |
32 | +#endif | |
33 | + switch(syscall) { | |
34 | + case __NR_open: | |
35 | + return 2; | |
36 | + case __NR_openat: | |
37 | + return 3; | |
38 | + case __NR_execve: | |
39 | + return 5; | |
40 | + default: | |
41 | + return 0; | |
42 | + } | |
43 | +} | |
44 | + | |
26 | 45 | static int __init audit_classes_init(void) |
27 | 46 | { |
28 | 47 | #ifdef CONFIG_IA32_EMULATION |
include/linux/audit.h
... | ... | @@ -181,6 +181,7 @@ |
181 | 181 | #define AUDIT_EXIT 103 |
182 | 182 | #define AUDIT_SUCCESS 104 /* exit >= 0; value ignored */ |
183 | 183 | #define AUDIT_WATCH 105 |
184 | +#define AUDIT_PERM 106 | |
184 | 185 | |
185 | 186 | #define AUDIT_ARG0 200 |
186 | 187 | #define AUDIT_ARG1 (AUDIT_ARG0+1) |
... | ... | @@ -256,6 +257,11 @@ |
256 | 257 | #define AUDIT_ARCH_V850 (EM_V850|__AUDIT_ARCH_LE) |
257 | 258 | #define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) |
258 | 259 | |
260 | +#define AUDIT_PERM_EXEC 1 | |
261 | +#define AUDIT_PERM_WRITE 2 | |
262 | +#define AUDIT_PERM_READ 4 | |
263 | +#define AUDIT_PERM_ATTR 8 | |
264 | + | |
259 | 265 | struct audit_status { |
260 | 266 | __u32 mask; /* Bit mask for valid entries */ |
261 | 267 | __u32 enabled; /* 1 = enabled, 0 = disabled */ |
... | ... | @@ -318,6 +324,7 @@ |
318 | 324 | #define AUDITSC_FAILURE 2 |
319 | 325 | #define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS ) |
320 | 326 | extern int __init audit_register_class(int class, unsigned *list); |
327 | +extern int audit_classify_syscall(int abi, unsigned syscall); | |
321 | 328 | #ifdef CONFIG_AUDITSYSCALL |
322 | 329 | /* These are defined in auditsc.c */ |
323 | 330 | /* Public API */ |
kernel/audit.h
... | ... | @@ -104,6 +104,7 @@ |
104 | 104 | return (ino & (AUDIT_INODE_BUCKETS-1)); |
105 | 105 | } |
106 | 106 | |
107 | +extern int audit_match_class(int class, unsigned syscall); | |
107 | 108 | extern int audit_comparator(const u32 left, const u32 op, const u32 right); |
108 | 109 | extern int audit_compare_dname_path(const char *dname, const char *path, |
109 | 110 | int *dirlen); |
kernel/auditfilter.c
... | ... | @@ -302,6 +302,15 @@ |
302 | 302 | return 0; |
303 | 303 | } |
304 | 304 | |
305 | +int audit_match_class(int class, unsigned syscall) | |
306 | +{ | |
307 | + if (unlikely(syscall >= AUDIT_BITMASK_SIZE * sizeof(__u32))) | |
308 | + return 0; | |
309 | + if (unlikely(class >= AUDIT_SYSCALL_CLASSES || !classes[class])) | |
310 | + return 0; | |
311 | + return classes[class][AUDIT_WORD(syscall)] & AUDIT_BIT(syscall); | |
312 | +} | |
313 | + | |
305 | 314 | /* Common user-space to kernel rule translation. */ |
306 | 315 | static inline struct audit_entry *audit_to_entry_common(struct audit_rule *rule) |
307 | 316 | { |
... | ... | @@ -414,6 +423,10 @@ |
414 | 423 | case AUDIT_ARG2: |
415 | 424 | case AUDIT_ARG3: |
416 | 425 | break; |
426 | + case AUDIT_PERM: | |
427 | + if (f->val & ~15) | |
428 | + goto exit_free; | |
429 | + break; | |
417 | 430 | case AUDIT_INODE: |
418 | 431 | err = audit_to_inode(&entry->rule, f); |
419 | 432 | if (err) |
... | ... | @@ -567,6 +580,10 @@ |
567 | 580 | goto exit_free; |
568 | 581 | entry->rule.buflen += f->val; |
569 | 582 | entry->rule.filterkey = str; |
583 | + break; | |
584 | + case AUDIT_PERM: | |
585 | + if (f->val & ~15) | |
586 | + goto exit_free; | |
570 | 587 | break; |
571 | 588 | default: |
572 | 589 | goto exit_free; |
kernel/auditsc.c
... | ... | @@ -209,6 +209,54 @@ |
209 | 209 | #endif |
210 | 210 | }; |
211 | 211 | |
212 | +#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE]) | |
213 | +static inline int open_arg(int flags, int mask) | |
214 | +{ | |
215 | + int n = ACC_MODE(flags); | |
216 | + if (flags & (O_TRUNC | O_CREAT)) | |
217 | + n |= AUDIT_PERM_WRITE; | |
218 | + return n & mask; | |
219 | +} | |
220 | + | |
221 | +static int audit_match_perm(struct audit_context *ctx, int mask) | |
222 | +{ | |
223 | + unsigned n = ctx->major; | |
224 | + switch (audit_classify_syscall(ctx->arch, n)) { | |
225 | + case 0: /* native */ | |
226 | + if ((mask & AUDIT_PERM_WRITE) && | |
227 | + audit_match_class(AUDIT_CLASS_WRITE, n)) | |
228 | + return 1; | |
229 | + if ((mask & AUDIT_PERM_READ) && | |
230 | + audit_match_class(AUDIT_CLASS_READ, n)) | |
231 | + return 1; | |
232 | + if ((mask & AUDIT_PERM_ATTR) && | |
233 | + audit_match_class(AUDIT_CLASS_CHATTR, n)) | |
234 | + return 1; | |
235 | + return 0; | |
236 | + case 1: /* 32bit on biarch */ | |
237 | + if ((mask & AUDIT_PERM_WRITE) && | |
238 | + audit_match_class(AUDIT_CLASS_WRITE_32, n)) | |
239 | + return 1; | |
240 | + if ((mask & AUDIT_PERM_READ) && | |
241 | + audit_match_class(AUDIT_CLASS_READ_32, n)) | |
242 | + return 1; | |
243 | + if ((mask & AUDIT_PERM_ATTR) && | |
244 | + audit_match_class(AUDIT_CLASS_CHATTR_32, n)) | |
245 | + return 1; | |
246 | + return 0; | |
247 | + case 2: /* open */ | |
248 | + return mask & ACC_MODE(ctx->argv[1]); | |
249 | + case 3: /* openat */ | |
250 | + return mask & ACC_MODE(ctx->argv[2]); | |
251 | + case 4: /* socketcall */ | |
252 | + return ((mask & AUDIT_PERM_WRITE) && ctx->argv[0] == SYS_BIND); | |
253 | + case 5: /* execve */ | |
254 | + return mask & AUDIT_PERM_EXEC; | |
255 | + default: | |
256 | + return 0; | |
257 | + } | |
258 | +} | |
259 | + | |
212 | 260 | /* Determine if any context name data matches a rule's watch data */ |
213 | 261 | /* Compare a task_struct with an audit_rule. Return 1 on match, 0 |
214 | 262 | * otherwise. */ |
... | ... | @@ -396,6 +444,9 @@ |
396 | 444 | case AUDIT_FILTERKEY: |
397 | 445 | /* ignore this field for filtering */ |
398 | 446 | result = 1; |
447 | + break; | |
448 | + case AUDIT_PERM: | |
449 | + result = audit_match_perm(ctx, f->val); | |
399 | 450 | break; |
400 | 451 | } |
401 | 452 |