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

x86/vm86/32: Remove VM86_SCREEN_BITMAP support

The implementation was rather buggy. It unconditionally marked PTEs
read-only, even for VM_SHARED mappings. I'm not sure whether this is
actually a problem, but it certainly seems unwise. More importantly, it
released the mmap lock before flushing the TLB, which could allow a racing
CoW operation to falsely believe that the underlying memory was not
writable.

I can't find any users at all of this mechanism, so just remove it.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Borislav Petkov <bp@suse.de>
Acked-by: Stas Sergeev <stsp2@yandex.ru>
Link: https://lkml.kernel.org/r/f3086de0babcab36f69949b5780bde851f719bc8.1611078018.git.luto@kernel.org

authored by

Andy Lutomirski and committed by
Borislav Petkov
8ece53ef b86cb292

+16 -81
-1
arch/x86/include/asm/vm86.h
··· 36 36 unsigned long saved_sp0; 37 37 38 38 unsigned long flags; 39 - unsigned long screen_bitmap; 40 39 unsigned long cpu_type; 41 40 struct revectored_struct int_revectored; 42 41 struct revectored_struct int21_revectored;
+2 -2
arch/x86/include/uapi/asm/vm86.h
··· 97 97 struct vm86_struct { 98 98 struct vm86_regs regs; 99 99 unsigned long flags; 100 - unsigned long screen_bitmap; 100 + unsigned long screen_bitmap; /* unused, preserved by vm86() */ 101 101 unsigned long cpu_type; 102 102 struct revectored_struct int_revectored; 103 103 struct revectored_struct int21_revectored; ··· 106 106 /* 107 107 * flags masks 108 108 */ 109 - #define VM86_SCREEN_BITMAP 0x0001 109 + #define VM86_SCREEN_BITMAP 0x0001 /* no longer supported */ 110 110 111 111 struct vm86plus_info_struct { 112 112 unsigned long force_return_for_pic:1;
+14 -48
arch/x86/kernel/vm86_32.c
··· 134 134 unsafe_put_user(regs->ds, &user->regs.ds, Efault_end); 135 135 unsafe_put_user(regs->fs, &user->regs.fs, Efault_end); 136 136 unsafe_put_user(regs->gs, &user->regs.gs, Efault_end); 137 - unsafe_put_user(vm86->screen_bitmap, &user->screen_bitmap, Efault_end); 137 + 138 + /* 139 + * Don't write screen_bitmap in case some user had a value there 140 + * and expected it to remain unchanged. 141 + */ 138 142 139 143 user_access_end(); 140 144 ··· 163 159 pr_alert("could not access userspace vm86 info\n"); 164 160 do_exit(SIGSEGV); 165 161 } 166 - 167 - static void mark_screen_rdonly(struct mm_struct *mm) 168 - { 169 - struct vm_area_struct *vma; 170 - spinlock_t *ptl; 171 - pgd_t *pgd; 172 - p4d_t *p4d; 173 - pud_t *pud; 174 - pmd_t *pmd; 175 - pte_t *pte; 176 - int i; 177 - 178 - mmap_write_lock(mm); 179 - pgd = pgd_offset(mm, 0xA0000); 180 - if (pgd_none_or_clear_bad(pgd)) 181 - goto out; 182 - p4d = p4d_offset(pgd, 0xA0000); 183 - if (p4d_none_or_clear_bad(p4d)) 184 - goto out; 185 - pud = pud_offset(p4d, 0xA0000); 186 - if (pud_none_or_clear_bad(pud)) 187 - goto out; 188 - pmd = pmd_offset(pud, 0xA0000); 189 - 190 - if (pmd_trans_huge(*pmd)) { 191 - vma = find_vma(mm, 0xA0000); 192 - split_huge_pmd(vma, pmd, 0xA0000); 193 - } 194 - if (pmd_none_or_clear_bad(pmd)) 195 - goto out; 196 - pte = pte_offset_map_lock(mm, pmd, 0xA0000, &ptl); 197 - for (i = 0; i < 32; i++) { 198 - if (pte_present(*pte)) 199 - set_pte(pte, pte_wrprotect(*pte)); 200 - pte++; 201 - } 202 - pte_unmap_unlock(pte, ptl); 203 - out: 204 - mmap_write_unlock(mm); 205 - flush_tlb_mm_range(mm, 0xA0000, 0xA0000 + 32*PAGE_SIZE, PAGE_SHIFT, false); 206 - } 207 - 208 - 209 162 210 163 static int do_vm86_irq_handling(int subfunction, int irqnumber); 211 164 static long do_sys_vm86(struct vm86plus_struct __user *user_vm86, bool plus); ··· 243 282 offsetof(struct vm86_struct, int_revectored))) 244 283 return -EFAULT; 245 284 285 + 286 + /* VM86_SCREEN_BITMAP had numerous bugs and appears to have no users. */ 287 + if (v.flags & VM86_SCREEN_BITMAP) { 288 + char comm[TASK_COMM_LEN]; 289 + 290 + pr_info_once("vm86: '%s' uses VM86_SCREEN_BITMAP, which is no longer supported\n", get_task_comm(comm, current)); 291 + return -EINVAL; 292 + } 293 + 246 294 memset(&vm86regs, 0, sizeof(vm86regs)); 247 295 248 296 vm86regs.pt.bx = v.regs.ebx; ··· 272 302 vm86regs.gs = v.regs.gs; 273 303 274 304 vm86->flags = v.flags; 275 - vm86->screen_bitmap = v.screen_bitmap; 276 305 vm86->cpu_type = v.cpu_type; 277 306 278 307 if (copy_from_user(&vm86->int_revectored, ··· 338 369 339 370 update_task_stack(tsk); 340 371 preempt_enable(); 341 - 342 - if (vm86->flags & VM86_SCREEN_BITMAP) 343 - mark_screen_rdonly(tsk->mm); 344 372 345 373 memcpy((struct kernel_vm86_regs *)regs, &vm86regs, sizeof(vm86regs)); 346 374 return regs->ax;
-30
arch/x86/mm/fault.c
··· 262 262 } 263 263 } 264 264 265 - /* 266 - * Did it hit the DOS screen memory VA from vm86 mode? 267 - */ 268 - static inline void 269 - check_v8086_mode(struct pt_regs *regs, unsigned long address, 270 - struct task_struct *tsk) 271 - { 272 - #ifdef CONFIG_VM86 273 - unsigned long bit; 274 - 275 - if (!v8086_mode(regs) || !tsk->thread.vm86) 276 - return; 277 - 278 - bit = (address - 0xA0000) >> PAGE_SHIFT; 279 - if (bit < 32) 280 - tsk->thread.vm86->screen_bitmap |= 1 << bit; 281 - #endif 282 - } 283 - 284 265 static bool low_pfn(unsigned long pfn) 285 266 { 286 267 return pfn < max_low_pfn; ··· 315 334 "******* Please consider a BIOS update.\n" 316 335 "******* Disabling USB legacy in the BIOS may also help.\n"; 317 336 #endif 318 - 319 - /* 320 - * No vm86 mode in 64-bit mode: 321 - */ 322 - static inline void 323 - check_v8086_mode(struct pt_regs *regs, unsigned long address, 324 - struct task_struct *tsk) 325 - { 326 - } 327 337 328 338 static int bad_address(void *p) 329 339 { ··· 1388 1416 mm_fault_error(regs, hw_error_code, address, fault); 1389 1417 return; 1390 1418 } 1391 - 1392 - check_v8086_mode(regs, address, tsk); 1393 1419 } 1394 1420 NOKPROBE_SYMBOL(do_user_addr_fault); 1395 1421