diff options
| -rw-r--r-- | arch/Kconfig | 18 | ||||
| -rw-r--r-- | arch/powerpc/kernel/Makefile | 5 | ||||
| -rw-r--r-- | block/blk-softirq.c | 2 | ||||
| -rw-r--r-- | drivers/char/random.c | 4 | ||||
| -rw-r--r-- | fs/namespace.c | 1 | ||||
| -rw-r--r-- | include/linux/compiler-gcc.h | 7 | ||||
| -rw-r--r-- | include/linux/compiler.h | 4 | ||||
| -rw-r--r-- | include/linux/fdtable.h | 2 | ||||
| -rw-r--r-- | include/linux/genhd.h | 2 | ||||
| -rw-r--r-- | include/linux/init.h | 5 | ||||
| -rw-r--r-- | include/linux/random.h | 15 | ||||
| -rw-r--r-- | init/main.c | 1 | ||||
| -rw-r--r-- | kernel/fork.c | 7 | ||||
| -rw-r--r-- | kernel/rcu/tiny.c | 2 | ||||
| -rw-r--r-- | kernel/rcu/tree.c | 2 | ||||
| -rw-r--r-- | kernel/sched/fair.c | 2 | ||||
| -rw-r--r-- | kernel/softirq.c | 4 | ||||
| -rw-r--r-- | kernel/time/timer.c | 2 | ||||
| -rw-r--r-- | lib/irq_poll.c | 2 | ||||
| -rw-r--r-- | lib/random32.c | 2 | ||||
| -rw-r--r-- | mm/page_alloc.c | 5 | ||||
| -rw-r--r-- | net/core/dev.c | 4 | ||||
| -rw-r--r-- | scripts/Makefile.gcc-plugins | 9 | ||||
| -rw-r--r-- | scripts/gcc-plugins/latent_entropy_plugin.c | 640 |
24 files changed, 725 insertions, 22 deletions
diff --git a/arch/Kconfig b/arch/Kconfig index 11d349561ece..659bdd079277 100644 --- a/arch/Kconfig +++ b/arch/Kconfig | |||
| @@ -383,6 +383,24 @@ config GCC_PLUGIN_SANCOV | |||
| 383 | gcc-4.5 on). It is based on the commit "Add fuzzing coverage support" | 383 | gcc-4.5 on). It is based on the commit "Add fuzzing coverage support" |
| 384 | by Dmitry Vyukov <dvyukov@google.com>. | 384 | by Dmitry Vyukov <dvyukov@google.com>. |
| 385 | 385 | ||
| 386 | config GCC_PLUGIN_LATENT_ENTROPY | ||
| 387 | bool "Generate some entropy during boot and runtime" | ||
| 388 | depends on GCC_PLUGINS | ||
| 389 | help | ||
| 390 | By saying Y here the kernel will instrument some kernel code to | ||
| 391 | extract some entropy from both original and artificially created | ||
| 392 | program state. This will help especially embedded systems where | ||
| 393 | there is little 'natural' source of entropy normally. The cost | ||
| 394 | is some slowdown of the boot process (about 0.5%) and fork and | ||
| 395 | irq processing. | ||
| 396 | |||
| 397 | Note that entropy extracted this way is not cryptographically | ||
| 398 | secure! | ||
| 399 | |||
| 400 | This plugin was ported from grsecurity/PaX. More information at: | ||
| 401 | * https://grsecurity.net/ | ||
| 402 | * https://pax.grsecurity.net/ | ||
| 403 | |||
| 386 | config HAVE_CC_STACKPROTECTOR | 404 | config HAVE_CC_STACKPROTECTOR |
| 387 | bool | 405 | bool |
| 388 | help | 406 | help |
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile index 6913f6725ce1..1925341dbb9c 100644 --- a/arch/powerpc/kernel/Makefile +++ b/arch/powerpc/kernel/Makefile | |||
| @@ -14,6 +14,11 @@ CFLAGS_prom_init.o += -fPIC | |||
| 14 | CFLAGS_btext.o += -fPIC | 14 | CFLAGS_btext.o += -fPIC |
| 15 | endif | 15 | endif |
| 16 | 16 | ||
| 17 | CFLAGS_cputable.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) | ||
| 18 | CFLAGS_init.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) | ||
| 19 | CFLAGS_btext.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) | ||
| 20 | CFLAGS_prom.o += $(DISABLE_LATENT_ENTROPY_PLUGIN) | ||
| 21 | |||
| 17 | ifdef CONFIG_FUNCTION_TRACER | 22 | ifdef CONFIG_FUNCTION_TRACER |
| 18 | # Do not trace early boot code | 23 | # Do not trace early boot code |
| 19 | CFLAGS_REMOVE_cputable.o = -mno-sched-epilog $(CC_FLAGS_FTRACE) | 24 | CFLAGS_REMOVE_cputable.o = -mno-sched-epilog $(CC_FLAGS_FTRACE) |
diff --git a/block/blk-softirq.c b/block/blk-softirq.c index 96631e6a22b9..06cf9807f49a 100644 --- a/block/blk-softirq.c +++ b/block/blk-softirq.c | |||
| @@ -18,7 +18,7 @@ static DEFINE_PER_CPU(struct list_head, blk_cpu_done); | |||
| 18 | * Softirq action handler - move entries to local list and loop over them | 18 | * Softirq action handler - move entries to local list and loop over them |
| 19 | * while passing them to the queue registered handler. | 19 | * while passing them to the queue registered handler. |
| 20 | */ | 20 | */ |
| 21 | static void blk_done_softirq(struct softirq_action *h) | 21 | static __latent_entropy void blk_done_softirq(struct softirq_action *h) |
| 22 | { | 22 | { |
| 23 | struct list_head *cpu_list, local_list; | 23 | struct list_head *cpu_list, local_list; |
| 24 | 24 | ||
diff --git a/drivers/char/random.c b/drivers/char/random.c index d131e152c8ce..d6876d506220 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c | |||
| @@ -479,8 +479,8 @@ static ssize_t _extract_entropy(struct entropy_store *r, void *buf, | |||
| 479 | 479 | ||
| 480 | static void crng_reseed(struct crng_state *crng, struct entropy_store *r); | 480 | static void crng_reseed(struct crng_state *crng, struct entropy_store *r); |
| 481 | static void push_to_pool(struct work_struct *work); | 481 | static void push_to_pool(struct work_struct *work); |
| 482 | static __u32 input_pool_data[INPUT_POOL_WORDS]; | 482 | static __u32 input_pool_data[INPUT_POOL_WORDS] __latent_entropy; |
| 483 | static __u32 blocking_pool_data[OUTPUT_POOL_WORDS]; | 483 | static __u32 blocking_pool_data[OUTPUT_POOL_WORDS] __latent_entropy; |
| 484 | 484 | ||
| 485 | static struct entropy_store input_pool = { | 485 | static struct entropy_store input_pool = { |
| 486 | .poolinfo = &poolinfo_table[0], | 486 | .poolinfo = &poolinfo_table[0], |
diff --git a/fs/namespace.c b/fs/namespace.c index 58aca9c931ac..e6c234b1a645 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -2824,6 +2824,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) | |||
| 2824 | return new_ns; | 2824 | return new_ns; |
| 2825 | } | 2825 | } |
| 2826 | 2826 | ||
| 2827 | __latent_entropy | ||
| 2827 | struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, | 2828 | struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, |
| 2828 | struct user_namespace *user_ns, struct fs_struct *new_fs) | 2829 | struct user_namespace *user_ns, struct fs_struct *new_fs) |
| 2829 | { | 2830 | { |
diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h index 573c5a18908f..432f5c97e18f 100644 --- a/include/linux/compiler-gcc.h +++ b/include/linux/compiler-gcc.h | |||
| @@ -188,6 +188,13 @@ | |||
| 188 | #endif /* GCC_VERSION >= 40300 */ | 188 | #endif /* GCC_VERSION >= 40300 */ |
| 189 | 189 | ||
| 190 | #if GCC_VERSION >= 40500 | 190 | #if GCC_VERSION >= 40500 |
| 191 | |||
| 192 | #ifndef __CHECKER__ | ||
| 193 | #ifdef LATENT_ENTROPY_PLUGIN | ||
| 194 | #define __latent_entropy __attribute__((latent_entropy)) | ||
| 195 | #endif | ||
| 196 | #endif | ||
| 197 | |||
| 191 | /* | 198 | /* |
| 192 | * Mark a position in code as unreachable. This can be used to | 199 | * Mark a position in code as unreachable. This can be used to |
| 193 | * suppress control flow warnings after asm blocks that transfer | 200 | * suppress control flow warnings after asm blocks that transfer |
diff --git a/include/linux/compiler.h b/include/linux/compiler.h index f1bfa15b6f9b..cf0fa5d86059 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h | |||
| @@ -429,6 +429,10 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s | |||
| 429 | # define __attribute_const__ /* unimplemented */ | 429 | # define __attribute_const__ /* unimplemented */ |
| 430 | #endif | 430 | #endif |
| 431 | 431 | ||
| 432 | #ifndef __latent_entropy | ||
| 433 | # define __latent_entropy | ||
| 434 | #endif | ||
| 435 | |||
| 432 | /* | 436 | /* |
| 433 | * Tell gcc if a function is cold. The compiler will assume any path | 437 | * Tell gcc if a function is cold. The compiler will assume any path |
| 434 | * directly leading to the call is unlikely. | 438 | * directly leading to the call is unlikely. |
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h index aca2a6a1d035..6e84b2cae6ad 100644 --- a/include/linux/fdtable.h +++ b/include/linux/fdtable.h | |||
| @@ -105,7 +105,7 @@ struct files_struct *get_files_struct(struct task_struct *); | |||
| 105 | void put_files_struct(struct files_struct *fs); | 105 | void put_files_struct(struct files_struct *fs); |
| 106 | void reset_files_struct(struct files_struct *); | 106 | void reset_files_struct(struct files_struct *); |
| 107 | int unshare_files(struct files_struct **); | 107 | int unshare_files(struct files_struct **); |
| 108 | struct files_struct *dup_fd(struct files_struct *, int *); | 108 | struct files_struct *dup_fd(struct files_struct *, int *) __latent_entropy; |
| 109 | void do_close_on_exec(struct files_struct *); | 109 | void do_close_on_exec(struct files_struct *); |
| 110 | int iterate_fd(struct files_struct *, unsigned, | 110 | int iterate_fd(struct files_struct *, unsigned, |
| 111 | int (*)(const void *, struct file *, unsigned), | 111 | int (*)(const void *, struct file *, unsigned), |
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 1dbf52f9c24b..e0341af6950e 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
| @@ -437,7 +437,7 @@ extern void disk_flush_events(struct gendisk *disk, unsigned int mask); | |||
| 437 | extern unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask); | 437 | extern unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask); |
| 438 | 438 | ||
| 439 | /* drivers/char/random.c */ | 439 | /* drivers/char/random.c */ |
| 440 | extern void add_disk_randomness(struct gendisk *disk); | 440 | extern void add_disk_randomness(struct gendisk *disk) __latent_entropy; |
| 441 | extern void rand_initialize_disk(struct gendisk *disk); | 441 | extern void rand_initialize_disk(struct gendisk *disk); |
| 442 | 442 | ||
| 443 | static inline sector_t get_start_sect(struct block_device *bdev) | 443 | static inline sector_t get_start_sect(struct block_device *bdev) |
diff --git a/include/linux/init.h b/include/linux/init.h index 024a0b5b3ed0..e30104ceb86d 100644 --- a/include/linux/init.h +++ b/include/linux/init.h | |||
| @@ -39,7 +39,7 @@ | |||
| 39 | 39 | ||
| 40 | /* These are for everybody (although not all archs will actually | 40 | /* These are for everybody (although not all archs will actually |
| 41 | discard it in modules) */ | 41 | discard it in modules) */ |
| 42 | #define __init __section(.init.text) __cold notrace | 42 | #define __init __section(.init.text) __cold notrace __latent_entropy |
| 43 | #define __initdata __section(.init.data) | 43 | #define __initdata __section(.init.data) |
| 44 | #define __initconst __section(.init.rodata) | 44 | #define __initconst __section(.init.rodata) |
| 45 | #define __exitdata __section(.exit.data) | 45 | #define __exitdata __section(.exit.data) |
| @@ -75,7 +75,8 @@ | |||
| 75 | #define __exit __section(.exit.text) __exitused __cold notrace | 75 | #define __exit __section(.exit.text) __exitused __cold notrace |
| 76 | 76 | ||
| 77 | /* Used for MEMORY_HOTPLUG */ | 77 | /* Used for MEMORY_HOTPLUG */ |
| 78 | #define __meminit __section(.meminit.text) __cold notrace | 78 | #define __meminit __section(.meminit.text) __cold notrace \ |
| 79 | __latent_entropy | ||
| 79 | #define __meminitdata __section(.meminit.data) | 80 | #define __meminitdata __section(.meminit.data) |
| 80 | #define __meminitconst __section(.meminit.rodata) | 81 | #define __meminitconst __section(.meminit.rodata) |
| 81 | #define __memexit __section(.memexit.text) __exitused __cold notrace | 82 | #define __memexit __section(.memexit.text) __exitused __cold notrace |
diff --git a/include/linux/random.h b/include/linux/random.h index f7bb7a355cf7..7bd2403e4fef 100644 --- a/include/linux/random.h +++ b/include/linux/random.h | |||
| @@ -18,9 +18,20 @@ struct random_ready_callback { | |||
| 18 | }; | 18 | }; |
| 19 | 19 | ||
| 20 | extern void add_device_randomness(const void *, unsigned int); | 20 | extern void add_device_randomness(const void *, unsigned int); |
| 21 | |||
| 22 | #if defined(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) && !defined(__CHECKER__) | ||
| 23 | static inline void add_latent_entropy(void) | ||
| 24 | { | ||
| 25 | add_device_randomness((const void *)&latent_entropy, | ||
| 26 | sizeof(latent_entropy)); | ||
| 27 | } | ||
| 28 | #else | ||
| 29 | static inline void add_latent_entropy(void) {} | ||
| 30 | #endif | ||
| 31 | |||
| 21 | extern void add_input_randomness(unsigned int type, unsigned int code, | 32 | extern void add_input_randomness(unsigned int type, unsigned int code, |
| 22 | unsigned int value); | 33 | unsigned int value) __latent_entropy; |
| 23 | extern void add_interrupt_randomness(int irq, int irq_flags); | 34 | extern void add_interrupt_randomness(int irq, int irq_flags) __latent_entropy; |
| 24 | 35 | ||
| 25 | extern void get_random_bytes(void *buf, int nbytes); | 36 | extern void get_random_bytes(void *buf, int nbytes); |
| 26 | extern int add_random_ready_callback(struct random_ready_callback *rdy); | 37 | extern int add_random_ready_callback(struct random_ready_callback *rdy); |
diff --git a/init/main.c b/init/main.c index a8a58e2794a5..2858be732f6d 100644 --- a/init/main.c +++ b/init/main.c | |||
| @@ -789,6 +789,7 @@ int __init_or_module do_one_initcall(initcall_t fn) | |||
| 789 | } | 789 | } |
| 790 | WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf); | 790 | WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf); |
| 791 | 791 | ||
| 792 | add_latent_entropy(); | ||
| 792 | return ret; | 793 | return ret; |
| 793 | } | 794 | } |
| 794 | 795 | ||
diff --git a/kernel/fork.c b/kernel/fork.c index 6d42242485cb..623259fc794d 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -547,7 +547,8 @@ free_tsk: | |||
| 547 | } | 547 | } |
| 548 | 548 | ||
| 549 | #ifdef CONFIG_MMU | 549 | #ifdef CONFIG_MMU |
| 550 | static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) | 550 | static __latent_entropy int dup_mmap(struct mm_struct *mm, |
| 551 | struct mm_struct *oldmm) | ||
| 551 | { | 552 | { |
| 552 | struct vm_area_struct *mpnt, *tmp, *prev, **pprev; | 553 | struct vm_area_struct *mpnt, *tmp, *prev, **pprev; |
| 553 | struct rb_node **rb_link, *rb_parent; | 554 | struct rb_node **rb_link, *rb_parent; |
| @@ -1441,7 +1442,8 @@ init_task_pid(struct task_struct *task, enum pid_type type, struct pid *pid) | |||
| 1441 | * parts of the process environment (as per the clone | 1442 | * parts of the process environment (as per the clone |
| 1442 | * flags). The actual kick-off is left to the caller. | 1443 | * flags). The actual kick-off is left to the caller. |
| 1443 | */ | 1444 | */ |
| 1444 | static struct task_struct *copy_process(unsigned long clone_flags, | 1445 | static __latent_entropy struct task_struct *copy_process( |
| 1446 | unsigned long clone_flags, | ||
| 1445 | unsigned long stack_start, | 1447 | unsigned long stack_start, |
| 1446 | unsigned long stack_size, | 1448 | unsigned long stack_size, |
| 1447 | int __user *child_tidptr, | 1449 | int __user *child_tidptr, |
| @@ -1926,6 +1928,7 @@ long _do_fork(unsigned long clone_flags, | |||
| 1926 | 1928 | ||
| 1927 | p = copy_process(clone_flags, stack_start, stack_size, | 1929 | p = copy_process(clone_flags, stack_start, stack_size, |
| 1928 | child_tidptr, NULL, trace, tls, NUMA_NO_NODE); | 1930 | child_tidptr, NULL, trace, tls, NUMA_NO_NODE); |
| 1931 | add_latent_entropy(); | ||
| 1929 | /* | 1932 | /* |
| 1930 | * Do this prior waking up the new thread - the thread pointer | 1933 | * Do this prior waking up the new thread - the thread pointer |
| 1931 | * might get invalid after that point, if the thread exits quickly. | 1934 | * might get invalid after that point, if the thread exits quickly. |
diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c index 944b1b491ed8..1898559e6b60 100644 --- a/kernel/rcu/tiny.c +++ b/kernel/rcu/tiny.c | |||
| @@ -170,7 +170,7 @@ static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) | |||
| 170 | false)); | 170 | false)); |
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | static void rcu_process_callbacks(struct softirq_action *unused) | 173 | static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused) |
| 174 | { | 174 | { |
| 175 | __rcu_process_callbacks(&rcu_sched_ctrlblk); | 175 | __rcu_process_callbacks(&rcu_sched_ctrlblk); |
| 176 | __rcu_process_callbacks(&rcu_bh_ctrlblk); | 176 | __rcu_process_callbacks(&rcu_bh_ctrlblk); |
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 7e2e03879c2e..69a5611a7e7c 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
| @@ -3013,7 +3013,7 @@ __rcu_process_callbacks(struct rcu_state *rsp) | |||
| 3013 | /* | 3013 | /* |
| 3014 | * Do RCU core processing for the current CPU. | 3014 | * Do RCU core processing for the current CPU. |
| 3015 | */ | 3015 | */ |
| 3016 | static void rcu_process_callbacks(struct softirq_action *unused) | 3016 | static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused) |
| 3017 | { | 3017 | { |
| 3018 | struct rcu_state *rsp; | 3018 | struct rcu_state *rsp; |
| 3019 | 3019 | ||
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 502e95a6e927..2d4ad72f8f3c 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c | |||
| @@ -8522,7 +8522,7 @@ static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle) { } | |||
| 8522 | * run_rebalance_domains is triggered when needed from the scheduler tick. | 8522 | * run_rebalance_domains is triggered when needed from the scheduler tick. |
| 8523 | * Also triggered for nohz idle balancing (with nohz_balancing_kick set). | 8523 | * Also triggered for nohz idle balancing (with nohz_balancing_kick set). |
| 8524 | */ | 8524 | */ |
| 8525 | static void run_rebalance_domains(struct softirq_action *h) | 8525 | static __latent_entropy void run_rebalance_domains(struct softirq_action *h) |
| 8526 | { | 8526 | { |
| 8527 | struct rq *this_rq = this_rq(); | 8527 | struct rq *this_rq = this_rq(); |
| 8528 | enum cpu_idle_type idle = this_rq->idle_balance ? | 8528 | enum cpu_idle_type idle = this_rq->idle_balance ? |
diff --git a/kernel/softirq.c b/kernel/softirq.c index 66762645f9e8..1bf81ef91375 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
| @@ -496,7 +496,7 @@ void __tasklet_hi_schedule_first(struct tasklet_struct *t) | |||
| 496 | } | 496 | } |
| 497 | EXPORT_SYMBOL(__tasklet_hi_schedule_first); | 497 | EXPORT_SYMBOL(__tasklet_hi_schedule_first); |
| 498 | 498 | ||
| 499 | static void tasklet_action(struct softirq_action *a) | 499 | static __latent_entropy void tasklet_action(struct softirq_action *a) |
| 500 | { | 500 | { |
| 501 | struct tasklet_struct *list; | 501 | struct tasklet_struct *list; |
| 502 | 502 | ||
| @@ -532,7 +532,7 @@ static void tasklet_action(struct softirq_action *a) | |||
| 532 | } | 532 | } |
| 533 | } | 533 | } |
| 534 | 534 | ||
| 535 | static void tasklet_hi_action(struct softirq_action *a) | 535 | static __latent_entropy void tasklet_hi_action(struct softirq_action *a) |
| 536 | { | 536 | { |
| 537 | struct tasklet_struct *list; | 537 | struct tasklet_struct *list; |
| 538 | 538 | ||
diff --git a/kernel/time/timer.c b/kernel/time/timer.c index 32bf6f75a8fe..2d47980a1bc4 100644 --- a/kernel/time/timer.c +++ b/kernel/time/timer.c | |||
| @@ -1633,7 +1633,7 @@ static inline void __run_timers(struct timer_base *base) | |||
| 1633 | /* | 1633 | /* |
| 1634 | * This function runs timers and the timer-tq in bottom half context. | 1634 | * This function runs timers and the timer-tq in bottom half context. |
| 1635 | */ | 1635 | */ |
| 1636 | static void run_timer_softirq(struct softirq_action *h) | 1636 | static __latent_entropy void run_timer_softirq(struct softirq_action *h) |
| 1637 | { | 1637 | { |
| 1638 | struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); | 1638 | struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); |
| 1639 | 1639 | ||
diff --git a/lib/irq_poll.c b/lib/irq_poll.c index 2be55692aa43..1d6565e81030 100644 --- a/lib/irq_poll.c +++ b/lib/irq_poll.c | |||
| @@ -74,7 +74,7 @@ void irq_poll_complete(struct irq_poll *iop) | |||
| 74 | } | 74 | } |
| 75 | EXPORT_SYMBOL(irq_poll_complete); | 75 | EXPORT_SYMBOL(irq_poll_complete); |
| 76 | 76 | ||
| 77 | static void irq_poll_softirq(struct softirq_action *h) | 77 | static void __latent_entropy irq_poll_softirq(struct softirq_action *h) |
| 78 | { | 78 | { |
| 79 | struct list_head *list = this_cpu_ptr(&blk_cpu_iopoll); | 79 | struct list_head *list = this_cpu_ptr(&blk_cpu_iopoll); |
| 80 | int rearm = 0, budget = irq_poll_budget; | 80 | int rearm = 0, budget = irq_poll_budget; |
diff --git a/lib/random32.c b/lib/random32.c index 915982b304bb..fa594b1140e6 100644 --- a/lib/random32.c +++ b/lib/random32.c | |||
| @@ -47,7 +47,7 @@ static inline void prandom_state_selftest(void) | |||
| 47 | } | 47 | } |
| 48 | #endif | 48 | #endif |
| 49 | 49 | ||
| 50 | static DEFINE_PER_CPU(struct rnd_state, net_rand_state); | 50 | static DEFINE_PER_CPU(struct rnd_state, net_rand_state) __latent_entropy; |
| 51 | 51 | ||
| 52 | /** | 52 | /** |
| 53 | * prandom_u32_state - seeded pseudo-random number generator. | 53 | * prandom_u32_state - seeded pseudo-random number generator. |
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ca423cc20b59..2b3bf6767d54 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
| @@ -91,6 +91,11 @@ EXPORT_PER_CPU_SYMBOL(_numa_mem_); | |||
| 91 | int _node_numa_mem_[MAX_NUMNODES]; | 91 | int _node_numa_mem_[MAX_NUMNODES]; |
| 92 | #endif | 92 | #endif |
| 93 | 93 | ||
| 94 | #ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY | ||
| 95 | volatile u64 latent_entropy __latent_entropy; | ||
| 96 | EXPORT_SYMBOL(latent_entropy); | ||
| 97 | #endif | ||
| 98 | |||
| 94 | /* | 99 | /* |
| 95 | * Array of node states. | 100 | * Array of node states. |
| 96 | */ | 101 | */ |
diff --git a/net/core/dev.c b/net/core/dev.c index f1fe26f66458..4bc19a164ba5 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -3845,7 +3845,7 @@ int netif_rx_ni(struct sk_buff *skb) | |||
| 3845 | } | 3845 | } |
| 3846 | EXPORT_SYMBOL(netif_rx_ni); | 3846 | EXPORT_SYMBOL(netif_rx_ni); |
| 3847 | 3847 | ||
| 3848 | static void net_tx_action(struct softirq_action *h) | 3848 | static __latent_entropy void net_tx_action(struct softirq_action *h) |
| 3849 | { | 3849 | { |
| 3850 | struct softnet_data *sd = this_cpu_ptr(&softnet_data); | 3850 | struct softnet_data *sd = this_cpu_ptr(&softnet_data); |
| 3851 | 3851 | ||
| @@ -5198,7 +5198,7 @@ out_unlock: | |||
| 5198 | return work; | 5198 | return work; |
| 5199 | } | 5199 | } |
| 5200 | 5200 | ||
| 5201 | static void net_rx_action(struct softirq_action *h) | 5201 | static __latent_entropy void net_rx_action(struct softirq_action *h) |
| 5202 | { | 5202 | { |
| 5203 | struct softnet_data *sd = this_cpu_ptr(&softnet_data); | 5203 | struct softnet_data *sd = this_cpu_ptr(&softnet_data); |
| 5204 | unsigned long time_limit = jiffies + 2; | 5204 | unsigned long time_limit = jiffies + 2; |
diff --git a/scripts/Makefile.gcc-plugins b/scripts/Makefile.gcc-plugins index 61f0e6db909b..060d2cb373db 100644 --- a/scripts/Makefile.gcc-plugins +++ b/scripts/Makefile.gcc-plugins | |||
| @@ -6,6 +6,12 @@ ifdef CONFIG_GCC_PLUGINS | |||
| 6 | 6 | ||
| 7 | gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so | 7 | gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so |
| 8 | 8 | ||
| 9 | gcc-plugin-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += latent_entropy_plugin.so | ||
| 10 | gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += -DLATENT_ENTROPY_PLUGIN | ||
| 11 | ifdef CONFIG_PAX_LATENT_ENTROPY | ||
| 12 | DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable | ||
| 13 | endif | ||
| 14 | |||
| 9 | ifdef CONFIG_GCC_PLUGIN_SANCOV | 15 | ifdef CONFIG_GCC_PLUGIN_SANCOV |
| 10 | ifeq ($(CFLAGS_KCOV),) | 16 | ifeq ($(CFLAGS_KCOV),) |
| 11 | # It is needed because of the gcc-plugin.sh and gcc version checks. | 17 | # It is needed because of the gcc-plugin.sh and gcc version checks. |
| @@ -21,7 +27,8 @@ ifdef CONFIG_GCC_PLUGINS | |||
| 21 | 27 | ||
| 22 | GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) | 28 | GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) |
| 23 | 29 | ||
| 24 | export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR SANCOV_PLUGIN | 30 | export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR |
| 31 | export SANCOV_PLUGIN DISABLE_LATENT_ENTROPY_PLUGIN | ||
| 25 | 32 | ||
| 26 | ifneq ($(PLUGINCC),) | 33 | ifneq ($(PLUGINCC),) |
| 27 | # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication. | 34 | # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication. |
diff --git a/scripts/gcc-plugins/latent_entropy_plugin.c b/scripts/gcc-plugins/latent_entropy_plugin.c new file mode 100644 index 000000000000..ff1939b804ae --- /dev/null +++ b/scripts/gcc-plugins/latent_entropy_plugin.c | |||
| @@ -0,0 +1,640 @@ | |||
| 1 | /* | ||
| 2 | * Copyright 2012-2016 by the PaX Team <pageexec@freemail.hu> | ||
| 3 | * Copyright 2016 by Emese Revfy <re.emese@gmail.com> | ||
| 4 | * Licensed under the GPL v2 | ||
| 5 | * | ||
| 6 | * Note: the choice of the license means that the compilation process is | ||
| 7 | * NOT 'eligible' as defined by gcc's library exception to the GPL v3, | ||
| 8 | * but for the kernel it doesn't matter since it doesn't link against | ||
| 9 | * any of the gcc libraries | ||
| 10 | * | ||
| 11 | * This gcc plugin helps generate a little bit of entropy from program state, | ||
| 12 | * used throughout the uptime of the kernel. Here is an instrumentation example: | ||
| 13 | * | ||
| 14 | * before: | ||
| 15 | * void __latent_entropy test(int argc, char *argv[]) | ||
| 16 | * { | ||
| 17 | * if (argc <= 1) | ||
| 18 | * printf("%s: no command arguments :(\n", *argv); | ||
| 19 | * else | ||
| 20 | * printf("%s: %d command arguments!\n", *argv, args - 1); | ||
| 21 | * } | ||
| 22 | * | ||
| 23 | * after: | ||
| 24 | * void __latent_entropy test(int argc, char *argv[]) | ||
| 25 | * { | ||
| 26 | * // latent_entropy_execute() 1. | ||
| 27 | * unsigned long local_entropy; | ||
| 28 | * // init_local_entropy() 1. | ||
| 29 | * void *local_entropy_frameaddr; | ||
| 30 | * // init_local_entropy() 3. | ||
| 31 | * unsigned long tmp_latent_entropy; | ||
| 32 | * | ||
| 33 | * // init_local_entropy() 2. | ||
| 34 | * local_entropy_frameaddr = __builtin_frame_address(0); | ||
| 35 | * local_entropy = (unsigned long) local_entropy_frameaddr; | ||
| 36 | * | ||
| 37 | * // init_local_entropy() 4. | ||
| 38 | * tmp_latent_entropy = latent_entropy; | ||
| 39 | * // init_local_entropy() 5. | ||
| 40 | * local_entropy ^= tmp_latent_entropy; | ||
| 41 | * | ||
| 42 | * // latent_entropy_execute() 3. | ||
| 43 | * if (argc <= 1) { | ||
| 44 | * // perturb_local_entropy() | ||
| 45 | * local_entropy += 4623067384293424948; | ||
| 46 | * printf("%s: no command arguments :(\n", *argv); | ||
| 47 | * // perturb_local_entropy() | ||
| 48 | * } else { | ||
| 49 | * local_entropy ^= 3896280633962944730; | ||
| 50 | * printf("%s: %d command arguments!\n", *argv, args - 1); | ||
| 51 | * } | ||
| 52 | * | ||
| 53 | * // latent_entropy_execute() 4. | ||
| 54 | * tmp_latent_entropy = rol(tmp_latent_entropy, local_entropy); | ||
| 55 | * latent_entropy = tmp_latent_entropy; | ||
| 56 | * } | ||
| 57 | * | ||
| 58 | * TODO: | ||
| 59 | * - add ipa pass to identify not explicitly marked candidate functions | ||
| 60 | * - mix in more program state (function arguments/return values, | ||
| 61 | * loop variables, etc) | ||
| 62 | * - more instrumentation control via attribute parameters | ||
| 63 | * | ||
| 64 | * BUGS: | ||
| 65 | * - none known | ||
| 66 | * | ||
| 67 | * Options: | ||
| 68 | * -fplugin-arg-latent_entropy_plugin-disable | ||
| 69 | * | ||
| 70 | * Attribute: __attribute__((latent_entropy)) | ||
| 71 | * The latent_entropy gcc attribute can be only on functions and variables. | ||
| 72 | * If it is on a function then the plugin will instrument it. If the attribute | ||
| 73 | * is on a variable then the plugin will initialize it with a random value. | ||
| 74 | * The variable must be an integer, an integer array type or a structure | ||
| 75 | * with integer fields. | ||
| 76 | */ | ||
| 77 | |||
| 78 | #include "gcc-common.h" | ||
| 79 | |||
| 80 | int plugin_is_GPL_compatible; | ||
| 81 | |||
| 82 | static GTY(()) tree latent_entropy_decl; | ||
| 83 | |||
| 84 | static struct plugin_info latent_entropy_plugin_info = { | ||
| 85 | .version = "201606141920vanilla", | ||
| 86 | .help = "disable\tturn off latent entropy instrumentation\n", | ||
| 87 | }; | ||
| 88 | |||
| 89 | static unsigned HOST_WIDE_INT seed; | ||
| 90 | /* | ||
| 91 | * get_random_seed() (this is a GCC function) generates the seed. | ||
| 92 | * This is a simple random generator without any cryptographic security because | ||
| 93 | * the entropy doesn't come from here. | ||
| 94 | */ | ||
| 95 | static unsigned HOST_WIDE_INT get_random_const(void) | ||
| 96 | { | ||
| 97 | unsigned int i; | ||
| 98 | unsigned HOST_WIDE_INT ret = 0; | ||
| 99 | |||
| 100 | for (i = 0; i < 8 * sizeof(ret); i++) { | ||
| 101 | ret = (ret << 1) | (seed & 1); | ||
| 102 | seed >>= 1; | ||
| 103 | if (ret & 1) | ||
| 104 | seed ^= 0xD800000000000000ULL; | ||
| 105 | } | ||
| 106 | |||
| 107 | return ret; | ||
| 108 | } | ||
| 109 | |||
| 110 | static tree tree_get_random_const(tree type) | ||
| 111 | { | ||
| 112 | unsigned long long mask; | ||
| 113 | |||
| 114 | mask = 1ULL << (TREE_INT_CST_LOW(TYPE_SIZE(type)) - 1); | ||
| 115 | mask = 2 * (mask - 1) + 1; | ||
| 116 | |||
| 117 | if (TYPE_UNSIGNED(type)) | ||
| 118 | return build_int_cstu(type, mask & get_random_const()); | ||
| 119 | return build_int_cst(type, mask & get_random_const()); | ||
| 120 | } | ||
| 121 | |||
| 122 | static tree handle_latent_entropy_attribute(tree *node, tree name, | ||
| 123 | tree args __unused, | ||
| 124 | int flags __unused, | ||
| 125 | bool *no_add_attrs) | ||
| 126 | { | ||
| 127 | tree type; | ||
| 128 | #if BUILDING_GCC_VERSION <= 4007 | ||
| 129 | VEC(constructor_elt, gc) *vals; | ||
| 130 | #else | ||
| 131 | vec<constructor_elt, va_gc> *vals; | ||
| 132 | #endif | ||
| 133 | |||
| 134 | switch (TREE_CODE(*node)) { | ||
| 135 | default: | ||
| 136 | *no_add_attrs = true; | ||
| 137 | error("%qE attribute only applies to functions and variables", | ||
| 138 | name); | ||
| 139 | break; | ||
| 140 | |||
| 141 | case VAR_DECL: | ||
| 142 | if (DECL_INITIAL(*node)) { | ||
| 143 | *no_add_attrs = true; | ||
| 144 | error("variable %qD with %qE attribute must not be initialized", | ||
| 145 | *node, name); | ||
| 146 | break; | ||
| 147 | } | ||
| 148 | |||
| 149 | if (!TREE_STATIC(*node)) { | ||
| 150 | *no_add_attrs = true; | ||
| 151 | error("variable %qD with %qE attribute must not be local", | ||
| 152 | *node, name); | ||
| 153 | break; | ||
| 154 | } | ||
| 155 | |||
| 156 | type = TREE_TYPE(*node); | ||
| 157 | switch (TREE_CODE(type)) { | ||
| 158 | default: | ||
| 159 | *no_add_attrs = true; | ||
| 160 | error("variable %qD with %qE attribute must be an integer or a fixed length integer array type or a fixed sized structure with integer fields", | ||
| 161 | *node, name); | ||
| 162 | break; | ||
| 163 | |||
| 164 | case RECORD_TYPE: { | ||
| 165 | tree fld, lst = TYPE_FIELDS(type); | ||
| 166 | unsigned int nelt = 0; | ||
| 167 | |||
| 168 | for (fld = lst; fld; nelt++, fld = TREE_CHAIN(fld)) { | ||
| 169 | tree fieldtype; | ||
| 170 | |||
| 171 | fieldtype = TREE_TYPE(fld); | ||
| 172 | if (TREE_CODE(fieldtype) == INTEGER_TYPE) | ||
| 173 | continue; | ||
| 174 | |||
| 175 | *no_add_attrs = true; | ||
| 176 | error("structure variable %qD with %qE attribute has a non-integer field %qE", | ||
| 177 | *node, name, fld); | ||
| 178 | break; | ||
| 179 | } | ||
| 180 | |||
| 181 | if (fld) | ||
| 182 | break; | ||
| 183 | |||
| 184 | #if BUILDING_GCC_VERSION <= 4007 | ||
| 185 | vals = VEC_alloc(constructor_elt, gc, nelt); | ||
| 186 | #else | ||
| 187 | vec_alloc(vals, nelt); | ||
| 188 | #endif | ||
| 189 | |||
| 190 | for (fld = lst; fld; fld = TREE_CHAIN(fld)) { | ||
| 191 | tree random_const, fld_t = TREE_TYPE(fld); | ||
| 192 | |||
| 193 | random_const = tree_get_random_const(fld_t); | ||
| 194 | CONSTRUCTOR_APPEND_ELT(vals, fld, random_const); | ||
| 195 | } | ||
| 196 | |||
| 197 | /* Initialize the fields with random constants */ | ||
| 198 | DECL_INITIAL(*node) = build_constructor(type, vals); | ||
| 199 | break; | ||
| 200 | } | ||
| 201 | |||
| 202 | /* Initialize the variable with a random constant */ | ||
| 203 | case INTEGER_TYPE: | ||
| 204 | DECL_INITIAL(*node) = tree_get_random_const(type); | ||
| 205 | break; | ||
| 206 | |||
| 207 | case ARRAY_TYPE: { | ||
| 208 | tree elt_type, array_size, elt_size; | ||
| 209 | unsigned int i, nelt; | ||
| 210 | HOST_WIDE_INT array_size_int, elt_size_int; | ||
| 211 | |||
| 212 | elt_type = TREE_TYPE(type); | ||
| 213 | elt_size = TYPE_SIZE_UNIT(TREE_TYPE(type)); | ||
| 214 | array_size = TYPE_SIZE_UNIT(type); | ||
| 215 | |||
| 216 | if (TREE_CODE(elt_type) != INTEGER_TYPE || !array_size | ||
| 217 | || TREE_CODE(array_size) != INTEGER_CST) { | ||
| 218 | *no_add_attrs = true; | ||
| 219 | error("array variable %qD with %qE attribute must be a fixed length integer array type", | ||
| 220 | *node, name); | ||
| 221 | break; | ||
| 222 | } | ||
| 223 | |||
| 224 | array_size_int = TREE_INT_CST_LOW(array_size); | ||
| 225 | elt_size_int = TREE_INT_CST_LOW(elt_size); | ||
| 226 | nelt = array_size_int / elt_size_int; | ||
| 227 | |||
| 228 | #if BUILDING_GCC_VERSION <= 4007 | ||
| 229 | vals = VEC_alloc(constructor_elt, gc, nelt); | ||
| 230 | #else | ||
| 231 | vec_alloc(vals, nelt); | ||
| 232 | #endif | ||
| 233 | |||
| 234 | for (i = 0; i < nelt; i++) { | ||
| 235 | tree cst = size_int(i); | ||
| 236 | tree rand_cst = tree_get_random_const(elt_type); | ||
| 237 | |||
| 238 | CONSTRUCTOR_APPEND_ELT(vals, cst, rand_cst); | ||
| 239 | } | ||
| 240 | |||
| 241 | /* | ||
| 242 | * Initialize the elements of the array with random | ||
| 243 | * constants | ||
| 244 | */ | ||
| 245 | DECL_INITIAL(*node) = build_constructor(type, vals); | ||
| 246 | break; | ||
| 247 | } | ||
| 248 | } | ||
| 249 | break; | ||
| 250 | |||
| 251 | case FUNCTION_DECL: | ||
| 252 | break; | ||
| 253 | } | ||
| 254 | |||
| 255 | return NULL_TREE; | ||
| 256 | } | ||
| 257 | |||
| 258 | static struct attribute_spec latent_entropy_attr = { | ||
| 259 | .name = "latent_entropy", | ||
| 260 | .min_length = 0, | ||
| 261 | .max_length = 0, | ||
| 262 | .decl_required = true, | ||
| 263 | .type_required = false, | ||
| 264 | .function_type_required = false, | ||
| 265 | .handler = handle_latent_entropy_attribute, | ||
| 266 | #if BUILDING_GCC_VERSION >= 4007 | ||
| 267 | .affects_type_identity = false | ||
| 268 | #endif | ||
| 269 | }; | ||
| 270 | |||
| 271 | static void register_attributes(void *event_data __unused, void *data __unused) | ||
| 272 | { | ||
| 273 | register_attribute(&latent_entropy_attr); | ||
| 274 | } | ||
| 275 | |||
| 276 | static bool latent_entropy_gate(void) | ||
| 277 | { | ||
| 278 | tree list; | ||
| 279 | |||
| 280 | /* don't bother with noreturn functions for now */ | ||
| 281 | if (TREE_THIS_VOLATILE(current_function_decl)) | ||
| 282 | return false; | ||
| 283 | |||
| 284 | /* gcc-4.5 doesn't discover some trivial noreturn functions */ | ||
| 285 | if (EDGE_COUNT(EXIT_BLOCK_PTR_FOR_FN(cfun)->preds) == 0) | ||
| 286 | return false; | ||
| 287 | |||
| 288 | list = DECL_ATTRIBUTES(current_function_decl); | ||
| 289 | return lookup_attribute("latent_entropy", list) != NULL_TREE; | ||
| 290 | } | ||
| 291 | |||
| 292 | static tree create_var(tree type, const char *name) | ||
| 293 | { | ||
| 294 | tree var; | ||
| 295 | |||
| 296 | var = create_tmp_var(type, name); | ||
| 297 | add_referenced_var(var); | ||
| 298 | mark_sym_for_renaming(var); | ||
| 299 | return var; | ||
| 300 | } | ||
| 301 | |||
| 302 | /* | ||
| 303 | * Set up the next operation and its constant operand to use in the latent | ||
| 304 | * entropy PRNG. When RHS is specified, the request is for perturbing the | ||
| 305 | * local latent entropy variable, otherwise it is for perturbing the global | ||
| 306 | * latent entropy variable where the two operands are already given by the | ||
| 307 | * local and global latent entropy variables themselves. | ||
| 308 | * | ||
| 309 | * The operation is one of add/xor/rol when instrumenting the local entropy | ||
| 310 | * variable and one of add/xor when perturbing the global entropy variable. | ||
| 311 | * Rotation is not used for the latter case because it would transmit less | ||
| 312 | * entropy to the global variable than the other two operations. | ||
| 313 | */ | ||
| 314 | static enum tree_code get_op(tree *rhs) | ||
| 315 | { | ||
| 316 | static enum tree_code op; | ||
| 317 | unsigned HOST_WIDE_INT random_const; | ||
| 318 | |||
| 319 | random_const = get_random_const(); | ||
| 320 | |||
| 321 | switch (op) { | ||
| 322 | case BIT_XOR_EXPR: | ||
| 323 | op = PLUS_EXPR; | ||
| 324 | break; | ||
| 325 | |||
| 326 | case PLUS_EXPR: | ||
| 327 | if (rhs) { | ||
| 328 | op = LROTATE_EXPR; | ||
| 329 | /* | ||
| 330 | * This code limits the value of random_const to | ||
| 331 | * the size of a wide int for the rotation | ||
| 332 | */ | ||
| 333 | random_const &= HOST_BITS_PER_WIDE_INT - 1; | ||
| 334 | break; | ||
| 335 | } | ||
| 336 | |||
| 337 | case LROTATE_EXPR: | ||
| 338 | default: | ||
| 339 | op = BIT_XOR_EXPR; | ||
| 340 | break; | ||
| 341 | } | ||
| 342 | if (rhs) | ||
| 343 | *rhs = build_int_cstu(unsigned_intDI_type_node, random_const); | ||
| 344 | return op; | ||
| 345 | } | ||
| 346 | |||
| 347 | static gimple create_assign(enum tree_code code, tree lhs, tree op1, | ||
| 348 | tree op2) | ||
| 349 | { | ||
| 350 | return gimple_build_assign_with_ops(code, lhs, op1, op2); | ||
| 351 | } | ||
| 352 | |||
| 353 | static void perturb_local_entropy(basic_block bb, tree local_entropy) | ||
| 354 | { | ||
| 355 | gimple_stmt_iterator gsi; | ||
| 356 | gimple assign; | ||
| 357 | tree rhs; | ||
| 358 | enum tree_code op; | ||
| 359 | |||
| 360 | op = get_op(&rhs); | ||
| 361 | assign = create_assign(op, local_entropy, local_entropy, rhs); | ||
| 362 | gsi = gsi_after_labels(bb); | ||
| 363 | gsi_insert_before(&gsi, assign, GSI_NEW_STMT); | ||
| 364 | update_stmt(assign); | ||
| 365 | } | ||
| 366 | |||
| 367 | static void __perturb_latent_entropy(gimple_stmt_iterator *gsi, | ||
| 368 | tree local_entropy) | ||
| 369 | { | ||
| 370 | gimple assign; | ||
| 371 | tree temp; | ||
| 372 | enum tree_code op; | ||
| 373 | |||
| 374 | /* 1. create temporary copy of latent_entropy */ | ||
| 375 | temp = create_var(unsigned_intDI_type_node, "tmp_latent_entropy"); | ||
| 376 | |||
| 377 | /* 2. read... */ | ||
| 378 | add_referenced_var(latent_entropy_decl); | ||
| 379 | mark_sym_for_renaming(latent_entropy_decl); | ||
| 380 | assign = gimple_build_assign(temp, latent_entropy_decl); | ||
| 381 | gsi_insert_before(gsi, assign, GSI_NEW_STMT); | ||
| 382 | update_stmt(assign); | ||
| 383 | |||
| 384 | /* 3. ...modify... */ | ||
| 385 | op = get_op(NULL); | ||
| 386 | assign = create_assign(op, temp, temp, local_entropy); | ||
| 387 | gsi_insert_after(gsi, assign, GSI_NEW_STMT); | ||
| 388 | update_stmt(assign); | ||
| 389 | |||
| 390 | /* 4. ...write latent_entropy */ | ||
| 391 | assign = gimple_build_assign(latent_entropy_decl, temp); | ||
| 392 | gsi_insert_after(gsi, assign, GSI_NEW_STMT); | ||
| 393 | update_stmt(assign); | ||
| 394 | } | ||
| 395 | |||
| 396 | static bool handle_tail_calls(basic_block bb, tree local_entropy) | ||
| 397 | { | ||
| 398 | gimple_stmt_iterator gsi; | ||
| 399 | |||
| 400 | for (gsi = gsi_start_bb(bb); !gsi_end_p(gsi); gsi_next(&gsi)) { | ||
| 401 | gcall *call; | ||
| 402 | gimple stmt = gsi_stmt(gsi); | ||
| 403 | |||
| 404 | if (!is_gimple_call(stmt)) | ||
| 405 | continue; | ||
| 406 | |||
| 407 | call = as_a_gcall(stmt); | ||
| 408 | if (!gimple_call_tail_p(call)) | ||
| 409 | continue; | ||
| 410 | |||
| 411 | __perturb_latent_entropy(&gsi, local_entropy); | ||
| 412 | return true; | ||
| 413 | } | ||
| 414 | |||
| 415 | return false; | ||
| 416 | } | ||
| 417 | |||
| 418 | static void perturb_latent_entropy(tree local_entropy) | ||
| 419 | { | ||
| 420 | edge_iterator ei; | ||
| 421 | edge e, last_bb_e; | ||
| 422 | basic_block last_bb; | ||
| 423 | |||
| 424 | gcc_assert(single_pred_p(EXIT_BLOCK_PTR_FOR_FN(cfun))); | ||
| 425 | last_bb_e = single_pred_edge(EXIT_BLOCK_PTR_FOR_FN(cfun)); | ||
| 426 | |||
| 427 | FOR_EACH_EDGE(e, ei, last_bb_e->src->preds) { | ||
| 428 | if (ENTRY_BLOCK_PTR_FOR_FN(cfun) == e->src) | ||
| 429 | continue; | ||
| 430 | if (EXIT_BLOCK_PTR_FOR_FN(cfun) == e->src) | ||
| 431 | continue; | ||
| 432 | |||
| 433 | handle_tail_calls(e->src, local_entropy); | ||
| 434 | } | ||
| 435 | |||
| 436 | last_bb = single_pred(EXIT_BLOCK_PTR_FOR_FN(cfun)); | ||
| 437 | if (!handle_tail_calls(last_bb, local_entropy)) { | ||
| 438 | gimple_stmt_iterator gsi = gsi_last_bb(last_bb); | ||
| 439 | |||
| 440 | __perturb_latent_entropy(&gsi, local_entropy); | ||
| 441 | } | ||
| 442 | } | ||
| 443 | |||
| 444 | static void init_local_entropy(basic_block bb, tree local_entropy) | ||
| 445 | { | ||
| 446 | gimple assign, call; | ||
| 447 | tree frame_addr, rand_const, tmp, fndecl, udi_frame_addr; | ||
| 448 | enum tree_code op; | ||
| 449 | unsigned HOST_WIDE_INT rand_cst; | ||
| 450 | gimple_stmt_iterator gsi = gsi_after_labels(bb); | ||
| 451 | |||
| 452 | /* 1. create local_entropy_frameaddr */ | ||
| 453 | frame_addr = create_var(ptr_type_node, "local_entropy_frameaddr"); | ||
| 454 | |||
| 455 | /* 2. local_entropy_frameaddr = __builtin_frame_address() */ | ||
| 456 | fndecl = builtin_decl_implicit(BUILT_IN_FRAME_ADDRESS); | ||
| 457 | call = gimple_build_call(fndecl, 1, integer_zero_node); | ||
| 458 | gimple_call_set_lhs(call, frame_addr); | ||
| 459 | gsi_insert_before(&gsi, call, GSI_NEW_STMT); | ||
| 460 | update_stmt(call); | ||
| 461 | |||
| 462 | udi_frame_addr = fold_convert(unsigned_intDI_type_node, frame_addr); | ||
| 463 | assign = gimple_build_assign(local_entropy, udi_frame_addr); | ||
| 464 | gsi_insert_after(&gsi, assign, GSI_NEW_STMT); | ||
| 465 | update_stmt(assign); | ||
| 466 | |||
| 467 | /* 3. create temporary copy of latent_entropy */ | ||
| 468 | tmp = create_var(unsigned_intDI_type_node, "tmp_latent_entropy"); | ||
| 469 | |||
| 470 | /* 4. read the global entropy variable into local entropy */ | ||
| 471 | add_referenced_var(latent_entropy_decl); | ||
| 472 | mark_sym_for_renaming(latent_entropy_decl); | ||
| 473 | assign = gimple_build_assign(tmp, latent_entropy_decl); | ||
| 474 | gsi_insert_after(&gsi, assign, GSI_NEW_STMT); | ||
| 475 | update_stmt(assign); | ||
| 476 | |||
| 477 | /* 5. mix local_entropy_frameaddr into local entropy */ | ||
| 478 | assign = create_assign(BIT_XOR_EXPR, local_entropy, local_entropy, tmp); | ||
| 479 | gsi_insert_after(&gsi, assign, GSI_NEW_STMT); | ||
| 480 | update_stmt(assign); | ||
| 481 | |||
| 482 | rand_cst = get_random_const(); | ||
| 483 | rand_const = build_int_cstu(unsigned_intDI_type_node, rand_cst); | ||
| 484 | op = get_op(NULL); | ||
| 485 | assign = create_assign(op, local_entropy, local_entropy, rand_const); | ||
| 486 | gsi_insert_after(&gsi, assign, GSI_NEW_STMT); | ||
| 487 | update_stmt(assign); | ||
| 488 | } | ||
| 489 | |||
| 490 | static bool create_latent_entropy_decl(void) | ||
| 491 | { | ||
| 492 | varpool_node_ptr node; | ||
| 493 | |||
| 494 | if (latent_entropy_decl != NULL_TREE) | ||
| 495 | return true; | ||
| 496 | |||
| 497 | FOR_EACH_VARIABLE(node) { | ||
| 498 | tree name, var = NODE_DECL(node); | ||
| 499 | |||
| 500 | if (DECL_NAME_LENGTH(var) < sizeof("latent_entropy") - 1) | ||
| 501 | continue; | ||
| 502 | |||
| 503 | name = DECL_NAME(var); | ||
| 504 | if (strcmp(IDENTIFIER_POINTER(name), "latent_entropy")) | ||
| 505 | continue; | ||
| 506 | |||
| 507 | latent_entropy_decl = var; | ||
| 508 | break; | ||
| 509 | } | ||
| 510 | |||
| 511 | return latent_entropy_decl != NULL_TREE; | ||
| 512 | } | ||
| 513 | |||
| 514 | static unsigned int latent_entropy_execute(void) | ||
| 515 | { | ||
| 516 | basic_block bb; | ||
| 517 | tree local_entropy; | ||
| 518 | |||
| 519 | if (!create_latent_entropy_decl()) | ||
| 520 | return 0; | ||
| 521 | |||
| 522 | /* prepare for step 2 below */ | ||
| 523 | gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); | ||
| 524 | bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); | ||
| 525 | if (!single_pred_p(bb)) { | ||
| 526 | split_edge(single_succ_edge(ENTRY_BLOCK_PTR_FOR_FN(cfun))); | ||
| 527 | gcc_assert(single_succ_p(ENTRY_BLOCK_PTR_FOR_FN(cfun))); | ||
| 528 | bb = single_succ(ENTRY_BLOCK_PTR_FOR_FN(cfun)); | ||
| 529 | } | ||
| 530 | |||
| 531 | /* 1. create the local entropy variable */ | ||
| 532 | local_entropy = create_var(unsigned_intDI_type_node, "local_entropy"); | ||
| 533 | |||
| 534 | /* 2. initialize the local entropy variable */ | ||
| 535 | init_local_entropy(bb, local_entropy); | ||
| 536 | |||
| 537 | bb = bb->next_bb; | ||
| 538 | |||
| 539 | /* | ||
| 540 | * 3. instrument each BB with an operation on the | ||
| 541 | * local entropy variable | ||
| 542 | */ | ||
| 543 | while (bb != EXIT_BLOCK_PTR_FOR_FN(cfun)) { | ||
| 544 | perturb_local_entropy(bb, local_entropy); | ||
| 545 | bb = bb->next_bb; | ||
| 546 | }; | ||
| 547 | |||
| 548 | /* 4. mix local entropy into the global entropy variable */ | ||
| 549 | perturb_latent_entropy(local_entropy); | ||
| 550 | return 0; | ||
| 551 | } | ||
| 552 | |||
| 553 | static void latent_entropy_start_unit(void *gcc_data __unused, | ||
| 554 | void *user_data __unused) | ||
| 555 | { | ||
| 556 | tree type, id; | ||
| 557 | int quals; | ||
| 558 | |||
| 559 | seed = get_random_seed(false); | ||
| 560 | |||
| 561 | if (in_lto_p) | ||
| 562 | return; | ||
| 563 | |||
| 564 | /* extern volatile u64 latent_entropy */ | ||
| 565 | gcc_assert(TYPE_PRECISION(long_long_unsigned_type_node) == 64); | ||
| 566 | quals = TYPE_QUALS(long_long_unsigned_type_node) | TYPE_QUAL_VOLATILE; | ||
| 567 | type = build_qualified_type(long_long_unsigned_type_node, quals); | ||
| 568 | id = get_identifier("latent_entropy"); | ||
| 569 | latent_entropy_decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, id, type); | ||
| 570 | |||
| 571 | TREE_STATIC(latent_entropy_decl) = 1; | ||
| 572 | TREE_PUBLIC(latent_entropy_decl) = 1; | ||
| 573 | TREE_USED(latent_entropy_decl) = 1; | ||
| 574 | DECL_PRESERVE_P(latent_entropy_decl) = 1; | ||
| 575 | TREE_THIS_VOLATILE(latent_entropy_decl) = 1; | ||
| 576 | DECL_EXTERNAL(latent_entropy_decl) = 1; | ||
| 577 | DECL_ARTIFICIAL(latent_entropy_decl) = 1; | ||
| 578 | lang_hooks.decls.pushdecl(latent_entropy_decl); | ||
| 579 | } | ||
| 580 | |||
| 581 | #define PASS_NAME latent_entropy | ||
| 582 | #define PROPERTIES_REQUIRED PROP_gimple_leh | PROP_cfg | ||
| 583 | #define TODO_FLAGS_FINISH TODO_verify_ssa | TODO_verify_stmts | TODO_dump_func \ | ||
| 584 | | TODO_update_ssa | ||
| 585 | #include "gcc-generate-gimple-pass.h" | ||
| 586 | |||
| 587 | int plugin_init(struct plugin_name_args *plugin_info, | ||
| 588 | struct plugin_gcc_version *version) | ||
| 589 | { | ||
| 590 | bool enabled = true; | ||
| 591 | const char * const plugin_name = plugin_info->base_name; | ||
| 592 | const int argc = plugin_info->argc; | ||
| 593 | const struct plugin_argument * const argv = plugin_info->argv; | ||
| 594 | int i; | ||
| 595 | |||
| 596 | struct register_pass_info latent_entropy_pass_info; | ||
| 597 | |||
| 598 | latent_entropy_pass_info.pass = make_latent_entropy_pass(); | ||
| 599 | latent_entropy_pass_info.reference_pass_name = "optimized"; | ||
| 600 | latent_entropy_pass_info.ref_pass_instance_number = 1; | ||
| 601 | latent_entropy_pass_info.pos_op = PASS_POS_INSERT_BEFORE; | ||
| 602 | static const struct ggc_root_tab gt_ggc_r_gt_latent_entropy[] = { | ||
| 603 | { | ||
| 604 | .base = &latent_entropy_decl, | ||
| 605 | .nelt = 1, | ||
| 606 | .stride = sizeof(latent_entropy_decl), | ||
| 607 | .cb = >_ggc_mx_tree_node, | ||
| 608 | .pchw = >_pch_nx_tree_node | ||
| 609 | }, | ||
| 610 | LAST_GGC_ROOT_TAB | ||
| 611 | }; | ||
| 612 | |||
| 613 | if (!plugin_default_version_check(version, &gcc_version)) { | ||
| 614 | error(G_("incompatible gcc/plugin versions")); | ||
| 615 | return 1; | ||
| 616 | } | ||
| 617 | |||
| 618 | for (i = 0; i < argc; ++i) { | ||
| 619 | if (!(strcmp(argv[i].key, "disable"))) { | ||
| 620 | enabled = false; | ||
| 621 | continue; | ||
| 622 | } | ||
| 623 | error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); | ||
| 624 | } | ||
| 625 | |||
| 626 | register_callback(plugin_name, PLUGIN_INFO, NULL, | ||
| 627 | &latent_entropy_plugin_info); | ||
| 628 | if (enabled) { | ||
| 629 | register_callback(plugin_name, PLUGIN_START_UNIT, | ||
| 630 | &latent_entropy_start_unit, NULL); | ||
| 631 | register_callback(plugin_name, PLUGIN_REGISTER_GGC_ROOTS, | ||
| 632 | NULL, (void *)>_ggc_r_gt_latent_entropy); | ||
| 633 | register_callback(plugin_name, PLUGIN_PASS_MANAGER_SETUP, NULL, | ||
| 634 | &latent_entropy_pass_info); | ||
| 635 | } | ||
| 636 | register_callback(plugin_name, PLUGIN_ATTRIBUTES, register_attributes, | ||
| 637 | NULL); | ||
| 638 | |||
| 639 | return 0; | ||
| 640 | } | ||
