Commit 55669bfa141b488be865341ed12e188967d11308

Authored by Al Viro
1 parent dc104fb323

[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
... ... @@ -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 */
... ... @@ -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;
... ... @@ -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