drivers/misc/lkdtm/bugs.c: add arithmetic overflow and array bounds checks
Adds LKDTM tests for arithmetic overflow (both signed and unsigned), as well as array bounds checking. Signed-off-by: Kees Cook <keescook@chromium.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Acked-by: Dmitry Vyukov <dvyukov@google.com> Cc: Alexander Potapenko <glider@google.com> Cc: Andrey Konovalov <andreyknvl@google.com> Cc: Andrey Ryabinin <aryabinin@virtuozzo.com> Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Dan Carpenter <dan.carpenter@oracle.com> Cc: Elena Petrova <lenaptr@google.com> Cc: "Gustavo A. R. Silva" <gustavo@embeddedor.com> Link: http://lkml.kernel.org/r/20200227193516.32566-4-keescook@chromium.org Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
277a10850f
Коммит
ae2e1aad3e
|
@ -11,6 +11,7 @@
|
|||
#include <linux/sched/signal.h>
|
||||
#include <linux/sched/task_stack.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
#include <asm/desc.h>
|
||||
|
@ -175,6 +176,80 @@ void lkdtm_HUNG_TASK(void)
|
|||
schedule();
|
||||
}
|
||||
|
||||
volatile unsigned int huge = INT_MAX - 2;
|
||||
volatile unsigned int ignored;
|
||||
|
||||
void lkdtm_OVERFLOW_SIGNED(void)
|
||||
{
|
||||
int value;
|
||||
|
||||
value = huge;
|
||||
pr_info("Normal signed addition ...\n");
|
||||
value += 1;
|
||||
ignored = value;
|
||||
|
||||
pr_info("Overflowing signed addition ...\n");
|
||||
value += 4;
|
||||
ignored = value;
|
||||
}
|
||||
|
||||
|
||||
void lkdtm_OVERFLOW_UNSIGNED(void)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
value = huge;
|
||||
pr_info("Normal unsigned addition ...\n");
|
||||
value += 1;
|
||||
ignored = value;
|
||||
|
||||
pr_info("Overflowing unsigned addition ...\n");
|
||||
value += 4;
|
||||
ignored = value;
|
||||
}
|
||||
|
||||
/* Intentially using old-style flex array definition of 1 byte. */
|
||||
struct array_bounds_flex_array {
|
||||
int one;
|
||||
int two;
|
||||
char data[1];
|
||||
};
|
||||
|
||||
struct array_bounds {
|
||||
int one;
|
||||
int two;
|
||||
char data[8];
|
||||
int three;
|
||||
};
|
||||
|
||||
void lkdtm_ARRAY_BOUNDS(void)
|
||||
{
|
||||
struct array_bounds_flex_array *not_checked;
|
||||
struct array_bounds *checked;
|
||||
volatile int i;
|
||||
|
||||
not_checked = kmalloc(sizeof(*not_checked) * 2, GFP_KERNEL);
|
||||
checked = kmalloc(sizeof(*checked) * 2, GFP_KERNEL);
|
||||
|
||||
pr_info("Array access within bounds ...\n");
|
||||
/* For both, touch all bytes in the actual member size. */
|
||||
for (i = 0; i < sizeof(checked->data); i++)
|
||||
checked->data[i] = 'A';
|
||||
/*
|
||||
* For the uninstrumented flex array member, also touch 1 byte
|
||||
* beyond to verify it is correctly uninstrumented.
|
||||
*/
|
||||
for (i = 0; i < sizeof(not_checked->data) + 1; i++)
|
||||
not_checked->data[i] = 'A';
|
||||
|
||||
pr_info("Array access beyond bounds ...\n");
|
||||
for (i = 0; i < sizeof(checked->data) + 1; i++)
|
||||
checked->data[i] = 'B';
|
||||
|
||||
kfree(not_checked);
|
||||
kfree(checked);
|
||||
}
|
||||
|
||||
void lkdtm_CORRUPT_LIST_ADD(void)
|
||||
{
|
||||
/*
|
||||
|
|
|
@ -130,6 +130,9 @@ static const struct crashtype crashtypes[] = {
|
|||
CRASHTYPE(HARDLOCKUP),
|
||||
CRASHTYPE(SPINLOCKUP),
|
||||
CRASHTYPE(HUNG_TASK),
|
||||
CRASHTYPE(OVERFLOW_SIGNED),
|
||||
CRASHTYPE(OVERFLOW_UNSIGNED),
|
||||
CRASHTYPE(ARRAY_BOUNDS),
|
||||
CRASHTYPE(EXEC_DATA),
|
||||
CRASHTYPE(EXEC_STACK),
|
||||
CRASHTYPE(EXEC_KMALLOC),
|
||||
|
|
|
@ -22,6 +22,9 @@ void lkdtm_SOFTLOCKUP(void);
|
|||
void lkdtm_HARDLOCKUP(void);
|
||||
void lkdtm_SPINLOCKUP(void);
|
||||
void lkdtm_HUNG_TASK(void);
|
||||
void lkdtm_OVERFLOW_SIGNED(void);
|
||||
void lkdtm_OVERFLOW_UNSIGNED(void);
|
||||
void lkdtm_ARRAY_BOUNDS(void);
|
||||
void lkdtm_CORRUPT_LIST_ADD(void);
|
||||
void lkdtm_CORRUPT_LIST_DEL(void);
|
||||
void lkdtm_CORRUPT_USER_DS(void);
|
||||
|
|
Загрузка…
Ссылка в новой задаче