s390x/mm/uaccess: Fix race between page table upgrade and uaccess

This fixes CVE-2020-11884 which allows for a local kernel crash or
 code execution.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJeny8gAAoJEBF7vIC1phx8eWYP/2R8iLZIKrpb58PVQFAECJYp
 EIiiZ3b68AdlKUa52iLXt+WYC2RDIrNdSIsUXVWtXSGPfuE/vsY2fF4seUfrAzzu
 2usvjcJA3y7l32Xmlqz1WPK+6JBfxjGvLM80pHTD3bQpOEymJ4ODhWlbDwmBVl6U
 oYRMZfNyy/J+xOE0P6XRewllq9Vbx6xBX2CVIV8PDM1ktrAj/Q4e9CqMBx7RT3Vf
 36/CR3numLA6l6xktFoqfs2WV85uORfC7+tuHXepmEartfLu2109WW+H8aNd33Bj
 wuKTMi5IJbvToRhL6tBY0yhTGxwVwhoD/CDFEl1Qdf8yJfaNHjlzzncEsZPBJxu2
 cOyaTNZgHbcg7EteSpB8l/VAS7aaVoeQ+oKHKstjsHzfLE5UGItcF92BWUVYuHlx
 UcOcbDC9glLgfFIujAfsaVnS+iLxz+tV7ftfzFZTNl4ZF568f2urMNQF5RbOVip2
 RZZz/7wxE22VwNRilM+8bqriW0or4zr/Wo1cZan+dZxNUDzT+uFlDrWrUGTKeNwf
 Fe7DplD82FVYGrbC66huVzq40/31TTKo8dxpAXK79ETJ53qKP3vAGJ0TOyrc4fHP
 9VdErI7Ij+igfnQdBzdJYNuQmFT2gbeoNfqU4eam4sYSFik/1jrqiJgUfUmjW0no
 ugnUhVZ13vkE+ZjYlP2W
 =F1vM
 -----END PGP SIGNATURE-----

Merge tag 'cve-2020-11884' from emailed bundle

Pull s390 fix from Christian Borntraeger:
 "Fix a race between page table upgrade and uaccess on s390.

  This fixes CVE-2020-11884 which allows for a local kernel crash or
  code execution"

* tag 'cve-2020-11884' from emailed bundle:
  s390/mm: fix page table upgrade vs 2ndary address mode accesses
This commit is contained in:
Linus Torvalds 2020-04-28 09:13:08 -07:00
commit 3f777e19d1
2 changed files with 18 additions and 2 deletions

View File

@ -64,10 +64,13 @@ mm_segment_t enable_sacf_uaccess(void)
{
mm_segment_t old_fs;
unsigned long asce, cr;
unsigned long flags;
old_fs = current->thread.mm_segment;
if (old_fs & 1)
return old_fs;
/* protect against a concurrent page table upgrade */
local_irq_save(flags);
current->thread.mm_segment |= 1;
asce = S390_lowcore.kernel_asce;
if (likely(old_fs == USER_DS)) {
@ -83,6 +86,7 @@ mm_segment_t enable_sacf_uaccess(void)
__ctl_load(asce, 7, 7);
set_cpu_flag(CIF_ASCE_SECONDARY);
}
local_irq_restore(flags);
return old_fs;
}
EXPORT_SYMBOL(enable_sacf_uaccess);

View File

@ -70,8 +70,20 @@ static void __crst_table_upgrade(void *arg)
{
struct mm_struct *mm = arg;
if (current->active_mm == mm)
set_user_asce(mm);
/* we must change all active ASCEs to avoid the creation of new TLBs */
if (current->active_mm == mm) {
S390_lowcore.user_asce = mm->context.asce;
if (current->thread.mm_segment == USER_DS) {
__ctl_load(S390_lowcore.user_asce, 1, 1);
/* Mark user-ASCE present in CR1 */
clear_cpu_flag(CIF_ASCE_PRIMARY);
}
if (current->thread.mm_segment == USER_DS_SACF) {
__ctl_load(S390_lowcore.user_asce, 7, 7);
/* enable_sacf_uaccess does all or nothing */
WARN_ON(!test_cpu_flag(CIF_ASCE_SECONDARY));
}
}
__tlb_flush_local();
}