[PATCH] audit: AUDIT_PERM support

add support for AUDIT_PERM predicate

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Al Viro 55669bfa dc104fb3

+236
+16
arch/i386/kernel/audit.c
··· 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);
+16
arch/ia64/ia32/audit.c
··· 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 + }
+19
arch/ia64/kernel/audit.c
··· 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
+21
arch/powerpc/kernel/audit.c
··· 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
+16
arch/powerpc/kernel/compat_audit.c
··· 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 + }
+21
arch/s390/kernel/audit.c
··· 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
+16
arch/s390/kernel/compat_audit.c
··· 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 + }
+16
arch/x86_64/ia32/audit.c
··· 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 + }
+19
arch/x86_64/kernel/audit.c
··· 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
+7
include/linux/audit.h
··· 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) ··· 257 256 #define AUDIT_ARCH_V850 (EM_V850|__AUDIT_ARCH_LE) 258 257 #define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) 259 258 259 + #define AUDIT_PERM_EXEC 1 260 + #define AUDIT_PERM_WRITE 2 261 + #define AUDIT_PERM_READ 4 262 + #define AUDIT_PERM_ATTR 8 263 + 260 264 struct audit_status { 261 265 __u32 mask; /* Bit mask for valid entries */ 262 266 __u32 enabled; /* 1 = enabled, 0 = disabled */ ··· 324 318 #define AUDITSC_FAILURE 2 325 319 #define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS ) 326 320 extern int __init audit_register_class(int class, unsigned *list); 321 + extern int audit_classify_syscall(int abi, unsigned syscall); 327 322 #ifdef CONFIG_AUDITSYSCALL 328 323 /* These are defined in auditsc.c */ 329 324 /* Public API */
+1
kernel/audit.h
··· 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);
+17
kernel/auditfilter.c
··· 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 { ··· 422 413 case AUDIT_ARG1: 423 414 case AUDIT_ARG2: 424 415 case AUDIT_ARG3: 416 + break; 417 + case AUDIT_PERM: 418 + if (f->val & ~15) 419 + goto exit_free; 425 420 break; 426 421 case AUDIT_INODE: 427 422 err = audit_to_inode(&entry->rule, f); ··· 580 567 goto exit_free; 581 568 entry->rule.buflen += f->val; 582 569 entry->rule.filterkey = str; 570 + break; 571 + case AUDIT_PERM: 572 + if (f->val & ~15) 573 + goto exit_free; 583 574 break; 584 575 default: 585 576 goto exit_free;
+51
kernel/auditsc.c
··· 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. */ ··· 444 396 case AUDIT_FILTERKEY: 445 397 /* ignore this field for filtering */ 446 398 result = 1; 399 + break; 400 + case AUDIT_PERM: 401 + result = audit_match_perm(ctx, f->val); 447 402 break; 448 403 } 449 404