Skip to content
  • Bart Oldeman's avatar
    x86, vm86: Fix preemption bug for int1 debug and int3 breakpoint handlers. · 6554287b
    Bart Oldeman authored
    Impact: fix kernel bug such as:
    BUG: scheduling while atomic: dosemu.bin/19680/0x00000004
    See also Ubuntu bug 455067 at
    https://bugs.launchpad.net/ubuntu/+source/linux/+bug/455067
    
    Commits 4915a35e
    ("Use preempt_conditional_sti/cli in do_int3, like on x86_64.")
    and 3d2a71a5
    ("x86, traps: converge do_debug handlers")
    started disabling preemption in int1 and int3 handlers on i386.
    The problem with vm86 is that the call to handle_vm86_trap() may jump
    straight to entry_32.S and never returns so preempt is never enabled
    again, and there is an imbalance in the preempt count.
    
    Commit be716615 ("x86, vm86:
    fix preemption bug"), which was later (accidentally?) reverted by commit
    08d68323
    
     ("hw-breakpoints: modifying
    generic debug exception to use thread-specific debug registers")
    fixed the problem for debug exceptions but not for breakpoints.
    
    There are three solutions to this problem.
    
    1. Reenable preemption before calling handle_vm86_trap(). This
    was the approach that was later reverted.
    
    2. Do not disable preemption for i386 in breakpoint and debug handlers.
    This was the situation before October 2008. As far as I understand
    preemption only needs to be disabled on x86_64 because a seperate stack is
    used, but it's nice to have things work the same way on
    i386 and x86_64.
    
    3. Let handle_vm86_trap() return instead of jumping to assembly code.
    By setting a flag in _TIF_WORK_MASK, either TIF_IRET or TIF_NOTIFY_RESUME,
    the code in entry_32.S is instructed to return to 32 bit mode from
    V86 mode. The logic in entry_32.S was already present to handle signals.
    (I chose TIF_IRET because it's slightly more efficient in
    do_notify_resume() in signal.c, but in fact TIF_IRET can probably be
    replaced by TIF_NOTIFY_RESUME everywhere.)
    
    I'm submitting approach 3, because I believe it is the most elegant
    and prevents future confusion. Still, an obvious
    preempt_conditional_cli(regs); is necessary in traps.c to correct the
    bug.
    
    [ hpa: This is technically a regression, but because:
      1. the regression is so old,
      2. the patch seems relatively high risk, justifying more testing, and
      3. we're late in the 2.6.36-rc cycle,
    
      I'm queuing it up for the 2.6.37 merge window.  It might, however,
      justify as a -stable backport at a latter time, hence Cc: stable. ]
    
    Signed-off-by: default avatarBart Oldeman <bartoldeman@users.sourceforge.net>
    LKML-Reference: <alpine.DEB.2.00.1009231312330.4732@localhost.localdomain>
    Cc: Frederic Weisbecker <fweisbec@gmail.com>
    Cc: K.Prasad <prasad@linux.vnet.ibm.com>
    Cc: Alan Stern <stern@rowland.harvard.edu>
    Cc: Alexander van Heukelum <heukelum@fastmail.fm>
    Cc: <stable@kernel.org>
    Signed-off-by: default avatarH. Peter Anvin <hpa@linux.intel.com>
    6554287b