• Hugh Dickins's avatar
    kaiser: load_new_mm_cr3() let SWITCH_USER_CR3 flush user · 404e1095
    Hugh Dickins authored
    We have many machines (Westmere, Sandybridge, Ivybridge) supporting
    PCID but not INVPCID: on these load_new_mm_cr3() simply crashed.
    
    Flushing user context inside load_new_mm_cr3() without the use of
    invpcid is difficult: momentarily switch from kernel to user context
    and back to do so?  I'm not sure whether that can be safely done at
    all, and would risk polluting user context with kernel internals,
    and kernel context with stale user externals.
    
    Instead, follow the hint in the comment that was there: change
    X86_CR3_PCID_USER_VAR to be a per-cpu variable, then load_new_mm_cr3()
    can leave a note in it, for SWITCH_USER_CR3 on return to userspace to
    flush user context TLB, instead of default X86_CR3_PCID_USER_NOFLUSH.
    
    Which works well enough that there's no need to do it this way only
    when invpcid is unsupported: it's a good alternative to invpcid here.
    But there's a couple of inlines in asm/tlbflush.h that need to do the
    same trick, so it's best to localize all this per-cpu business in
    mm/kaiser.c: moving that part of the initialization from setup_pcid()
    to kaiser_setup_pcid(); with kaiser_flush_tlb_on_return_to_user() the
    function for noting an X86_CR3_PCID_USER_FLUSH.  And let's keep a
    KAISER_SHADOW_PGD_OFFSET in there, to avoid the extra OR on exit.
    
    I did try to make the feature tests in asm/tlbflush.h more consistent
    with each other: there seem to be far too many ways of performing such
    tests, and I don't have a good grasp of their differences.  At first
    I converted them all to be static_cpu_has(): but that proved to be a
    mistake, as the comment in __native_flush_tlb_single() hints; so then
    I reversed and made them all this_cpu_has().  Probably all gratuitous
    change, but that's the way it's working at present.
    
    I am slightly bothered by the way non-per-cpu X86_CR3_PCID_KERN_VAR
    gets re-initialized by each cpu (before and after these changes):
    no problem when (as usual) all cpus on a machine have the same
    features, but in principle incorrect.  However, my experiment
    to per-cpu-ify that one did not end well...
    Acked-by: default avatarJiri Kosina <jkosina@suse.cz>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    
    CVE-2017-5754
    Signed-off-by: default avatarColin Ian King <colin.king@canonical.com>
    Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
    404e1095
tlb.c 13.3 KB