/* { dg-do compile } */ /* { dg-options "-fanalyzer" } */ /* { dg-require-effective-target analyzer } */ #include "test-uaccess.h" /* Adapted and simplified decls from linux kernel headers. */ typedef unsigned char u8; typedef unsigned __INT16_TYPE__ u16; typedef unsigned __INT32_TYPE__ u32; typedef signed __INT32_TYPE__ s32; typedef __SIZE_TYPE__ size_t; #define EFAULT 14 typedef unsigned int gfp_t; #define GFP_KERNEL 0 void kfree(const void *); void *kmalloc(size_t size, gfp_t flags) __attribute__((malloc (kfree))); /* Adapted from antipatterns.ko:taint.c (GPL-v2.0). */ struct cmd_1 { u32 idx; u32 val; }; static u32 arr[16]; int taint_array_access(void __user *src) { struct cmd_1 cmd; if (copy_from_user(&cmd, src, sizeof(cmd))) return -EFAULT; /* * cmd.idx is an unsanitized value from user-space, hence * this is an arbitrary kernel memory access. */ arr[cmd.idx] = cmd.val; /* { dg-warning "use of attacker-controlled value 'cmd.idx' in array lookup without upper-bounds checking" } */ return 0; } struct cmd_2 { s32 idx; u32 val; }; int taint_signed_array_access(void __user *src) { struct cmd_2 cmd; if (copy_from_user(&cmd, src, sizeof(cmd))) return -EFAULT; if (cmd.idx >= 16) return -EFAULT; /* * cmd.idx hasn't been checked for being negative, hence * this is an arbitrary kernel memory access. */ arr[cmd.idx] = cmd.val; /* { dg-warning "use of attacker-controlled value 'cmd.idx' in array lookup without checking for negative" } */ return 0; } struct cmd_s32_binop { s32 a; s32 b; s32 result; }; int taint_divide_by_zero_direct(void __user *uptr) { struct cmd_s32_binop cmd; if (copy_from_user(&cmd, uptr, sizeof(cmd))) return -EFAULT; /* cmd.b is attacker-controlled and could be zero */ cmd.result = cmd.a / cmd.b; /* { dg-warning "use of attacker-controlled value 'cmd.b' as divisor without checking for zero" } */ if (copy_to_user (uptr, &cmd, sizeof(cmd))) return -EFAULT; return 0; } int taint_divide_by_zero_compound(void __user *uptr) { struct cmd_s32_binop cmd; if (copy_from_user(&cmd, uptr, sizeof(cmd))) return -EFAULT; /* * cmd.b is attacker-controlled and could be -1, hence * the divisor could be zero */ cmd.result = cmd.a / (cmd.b + 1); /* { dg-warning "use of attacker-controlled value 'cmd.b \\+ 1' as divisor without checking for zero" } */ if (copy_to_user (uptr, &cmd, sizeof(cmd))) return -EFAULT; return 0; } int taint_mod_by_zero_direct(void __user *uptr) { struct cmd_s32_binop cmd; if (copy_from_user(&cmd, uptr, sizeof(cmd))) return -EFAULT; /* cmd.b is attacker-controlled and could be zero */ cmd.result = cmd.a % cmd.b; /* { dg-warning "use of attacker-controlled value 'cmd.b' as divisor without checking for zero" } */ if (copy_to_user (uptr, &cmd, sizeof(cmd))) return -EFAULT; return 0; } int taint_mod_by_zero_compound(void __user *uptr) { struct cmd_s32_binop cmd; if (copy_from_user(&cmd, uptr, sizeof(cmd))) return -EFAULT; /* * cmd.b is attacker-controlled and could be -1, hence * the divisor could be zero */ cmd.result = cmd.a % (cmd.b + 1); /* { dg-warning "use of attacker-controlled value 'cmd.b \\+ 1' as divisor without checking for zero" } */ if (copy_to_user (uptr, &cmd, sizeof(cmd))) return -EFAULT; return 0; } /* TODO: etc. */