Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PATCH] seccomp: tsc disable

I believe at least for seccomp it's worth to turn off the tsc, not just for
HT but for the L2 cache too. So it's up to you, either you turn it off
completely (which isn't very nice IMHO) or I recommend to apply this below
patch.

This has been tested successfully on x86-64 against current cogito
repository (i686 compiles so I didn't bother testing ;). People selling
the cpu through cpushare may appreciate this bit for a peace of mind.

There's no way to get any timing info anymore with this applied
(gettimeofday is forbidden of course). The seccomp environment is
completely deterministic so it can't be allowed to get timing info, it has
to be deterministic so in the future I can enable a computing mode that
does a parallel computing for each task with server side transparent
checkpointing and verification that the output is the same from all the 2/3
seller computers for each task, without the buyer even noticing (for now
the verification is left to the buyer client side and there's no
checkpointing, since that would require more kernel changes to track the
dirty bits but it'll be easy to extend once the basic mode is finished).

Eliminating a cold-cache read of the cr4 global variable will save one
cacheline during the tlb flush while making the code per-cpu-safe at the
same time. Thanks to Mikael Pettersson for noticing the tlb flush wasn't
per-cpu-safe.

The global tlb flush can run from irq (IPI calling do_flush_tlb_all) but
it'll be transparent to the switch_to code since the IPI won't make any
change to the cr4 contents from the point of view of the interrupted code
and since it's now all per-cpu stuff, it will not race. So no need to
disable irqs in switch_to slow path.

Signed-off-by: Andrea Arcangeli <andrea@cpushare.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Andrea Arcangeli and committed by
Linus Torvalds
ffaa8bd6 6ae3db11

+82 -10
+29
arch/i386/kernel/process.c
··· 617 617 } 618 618 619 619 /* 620 + * This function selects if the context switch from prev to next 621 + * has to tweak the TSC disable bit in the cr4. 622 + */ 623 + static inline void disable_tsc(struct task_struct *prev_p, 624 + struct task_struct *next_p) 625 + { 626 + struct thread_info *prev, *next; 627 + 628 + /* 629 + * gcc should eliminate the ->thread_info dereference if 630 + * has_secure_computing returns 0 at compile time (SECCOMP=n). 631 + */ 632 + prev = prev_p->thread_info; 633 + next = next_p->thread_info; 634 + 635 + if (has_secure_computing(prev) || has_secure_computing(next)) { 636 + /* slow path here */ 637 + if (has_secure_computing(prev) && 638 + !has_secure_computing(next)) { 639 + write_cr4(read_cr4() & ~X86_CR4_TSD); 640 + } else if (!has_secure_computing(prev) && 641 + has_secure_computing(next)) 642 + write_cr4(read_cr4() | X86_CR4_TSD); 643 + } 644 + } 645 + 646 + /* 620 647 * switch_to(x,yn) should switch tasks from x to y. 621 648 * 622 649 * We fsave/fwait so that an exception goes off at the right time ··· 721 694 722 695 if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr)) 723 696 handle_io_bitmap(next, tss); 697 + 698 + disable_tsc(prev_p, next_p); 724 699 725 700 return prev_p; 726 701 }
+29
arch/x86_64/kernel/process.c
··· 482 482 } 483 483 484 484 /* 485 + * This function selects if the context switch from prev to next 486 + * has to tweak the TSC disable bit in the cr4. 487 + */ 488 + static inline void disable_tsc(struct task_struct *prev_p, 489 + struct task_struct *next_p) 490 + { 491 + struct thread_info *prev, *next; 492 + 493 + /* 494 + * gcc should eliminate the ->thread_info dereference if 495 + * has_secure_computing returns 0 at compile time (SECCOMP=n). 496 + */ 497 + prev = prev_p->thread_info; 498 + next = next_p->thread_info; 499 + 500 + if (has_secure_computing(prev) || has_secure_computing(next)) { 501 + /* slow path here */ 502 + if (has_secure_computing(prev) && 503 + !has_secure_computing(next)) { 504 + write_cr4(read_cr4() & ~X86_CR4_TSD); 505 + } else if (!has_secure_computing(prev) && 506 + has_secure_computing(next)) 507 + write_cr4(read_cr4() | X86_CR4_TSD); 508 + } 509 + } 510 + 511 + /* 485 512 * This special macro can be used to load a debugging register 486 513 */ 487 514 #define loaddebug(thread,r) set_debug(thread->debugreg ## r, r) ··· 625 598 memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); 626 599 } 627 600 } 601 + 602 + disable_tsc(prev_p, next_p); 628 603 629 604 return prev_p; 630 605 }
+7 -5
include/asm-i386/tlbflush.h
··· 22 22 */ 23 23 #define __flush_tlb_global() \ 24 24 do { \ 25 - unsigned int tmpreg; \ 25 + unsigned int tmpreg, cr4, cr4_orig; \ 26 26 \ 27 27 __asm__ __volatile__( \ 28 - "movl %1, %%cr4; # turn off PGE \n" \ 28 + "movl %%cr4, %2; # turn off PGE \n" \ 29 + "movl %2, %1; \n" \ 30 + "andl %3, %1; \n" \ 31 + "movl %1, %%cr4; \n" \ 29 32 "movl %%cr3, %0; \n" \ 30 33 "movl %0, %%cr3; # flush TLB \n" \ 31 34 "movl %2, %%cr4; # turn PGE back on \n" \ 32 - : "=&r" (tmpreg) \ 33 - : "r" (mmu_cr4_features & ~X86_CR4_PGE), \ 34 - "r" (mmu_cr4_features) \ 35 + : "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig) \ 36 + : "i" (~X86_CR4_PGE) \ 35 37 : "memory"); \ 36 38 } while (0) 37 39
+7 -5
include/asm-x86_64/tlbflush.h
··· 22 22 */ 23 23 #define __flush_tlb_global() \ 24 24 do { \ 25 - unsigned long tmpreg; \ 25 + unsigned long tmpreg, cr4, cr4_orig; \ 26 26 \ 27 27 __asm__ __volatile__( \ 28 - "movq %1, %%cr4; # turn off PGE \n" \ 28 + "movq %%cr4, %2; # turn off PGE \n" \ 29 + "movq %2, %1; \n" \ 30 + "andq %3, %1; \n" \ 31 + "movq %1, %%cr4; \n" \ 29 32 "movq %%cr3, %0; # flush TLB \n" \ 30 33 "movq %0, %%cr3; \n" \ 31 34 "movq %2, %%cr4; # turn PGE back on \n" \ 32 - : "=&r" (tmpreg) \ 33 - : "r" (mmu_cr4_features & ~X86_CR4_PGE), \ 34 - "r" (mmu_cr4_features) \ 35 + : "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig) \ 36 + : "i" (~X86_CR4_PGE) \ 35 37 : "memory"); \ 36 38 } while (0) 37 39
+10
include/linux/seccomp.h
··· 19 19 __secure_computing(this_syscall); 20 20 } 21 21 22 + static inline int has_secure_computing(struct thread_info *ti) 23 + { 24 + return unlikely(test_ti_thread_flag(ti, TIF_SECCOMP)); 25 + } 26 + 22 27 #else /* CONFIG_SECCOMP */ 23 28 24 29 #if (__GNUC__ > 2) ··· 33 28 #endif 34 29 35 30 #define secure_computing(x) do { } while (0) 31 + /* static inline to preserve typechecking */ 32 + static inline int has_secure_computing(struct thread_info *ti) 33 + { 34 + return 0; 35 + } 36 36 37 37 #endif /* CONFIG_SECCOMP */ 38 38