Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 26 May 2015 18:03:52 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        John-Mark Gurney <jmg@funkthat.com>
Cc:        Ian Lepore <ian@freebsd.org>, src-committers@freebsd.org,  svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   Re: svn commit: r283547 - head/sys/arm/conf
Message-ID:  <20150526153023.F914@besplex.bde.org>
In-Reply-To: <20150525235147.GJ37063@funkthat.com>
References:  <201505252327.t4PNRDaA033870@svn.freebsd.org> <20150525235147.GJ37063@funkthat.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, 25 May 2015, John-Mark Gurney wrote:

> Ian Lepore wrote this message on Mon, May 25, 2015 at 23:27 +0000:
>> Author: ian
>> Date: Mon May 25 23:27:13 2015
>> New Revision: 283547
>> URL: https://svnweb.freebsd.org/changeset/base/283547
>>
>> Log:
>>   Ensure that all arm kernel configs contain ALT_BREAK_TO_DEBUGGER and not
>>   BREAK_TO_DEBUGGER if they have a serial console (most do).  A burst of
>>   serial line noise (such as unplugging a usb serial adapter) can look like
>>   a break and drop a working system into the debugger.  The alt break sequence
>>   (<CR>~^B) works fine on both serial and non-serial consoles.
>
> Just so you know, this removes support for video console to break into
> the debugger via keyboard...  This mean ctrl-alt-esc and other key
> sequences won't work anymore...

Actually, it only breaks the usual non-sequences ctrl-prtscrn and
ctrl-alt-esc.  All console drivers support ALT_BREAK_TO_DEBUGGER, so
escape sequences still work if this option is configured, but these
quences are harder to remember and harder to type (I often forget
where \n goes in them, or mistype it) and were not needed before
except for serial consoles, so at most users of serial consoles will
know them.

Most of this is broken.

1. The BREAK in BREAK_TO_DEBUGGER means a serial line break.  This is now
    confused with "breaking" into the debugger in all sorts of ways, and/or
    with the breakpoint() function used to implement "breaking" into the
    debugger in some of these ways.   The breakpoint() function has a
    generic name although not all arches have a breakpoint instruction in
    hardware, at least by name.  kdb_break() is misnamed.  It is just a
    wrapper for kdb_enter() that supplies the (wrong) entry code
    KDB_WHY_BREAK and the (wrong) message "Break to debugger".  Here
    BREAK and "Break" have nothing to do with serial line breaks or the
    (virtual) breakpoint instruction.  They mean "break" in the sense of
    "stop the normal execution and enter the debugger".  Normal uses of
    the breakpoint instruction don't go via this path -- they have already
    executed the instruction, while this path will execute the instruction.

2. BREAK_TO_DEBUGGER with its non-broken meaning is unusable for most
    systems since it causes the problems mentioned by ian, except the
    problems are not really line noise.  Just unplugging the line causes
    a serial line break unless you are quick enough to re-plug it in
    less than the break detection time, and no one can do that except
    at low speeds like 1 bit/second, since the break detection time is
    just 1 character times.  Unplugging is also less of a problem than
    turning off the terminal, since with the former you are more likely
    to see that the system has entered the debugger immediately after
    re-plugging, instead of much later when turning on the terminal.

    I didn't notice this problem for many years.  Even BREAK_TO_DEBUGGER
    was only added in 1996.  Before that, serial line breaks caused
    debugger entry unconditionally if a debugger was configured.  Just
    before that, until 1995 debugger entry was similarly unconditional
    except it occured when a slip FRAME_END character (0xc0) was received.
    I don't see how slip could have worked with that.  I didn't notice
    the problem with unplugging for many more years.  There was a bug in
    detecting these line breaks.  Serial interrupts were only enabled when
    the console was open for normal syscalls and the line breaks were not
    detected otherwise, so they didn't bite as often as they should have.

3. So BREAK_TO_DEBUGGER should normally not be configured.
    ALT_BREAK_TO_DEBUGGER used to provide an adequate workaround.  The
    name of this option is confusing but not wrong.  I gives an
    alternative to entering the debugger with a serial line break,
    not an alternative to the normal way of breaking into the debugger.

4. Breakage started occuring with multiple consoles.  You might have
    1 serial console that is most secure and never turned off, so
    BREAK_TO_DEBUGGER is best for it, 1 serial console that is secure
    but sometimes turned off, so ALT_BREAK_TO_DEBUGGER is best for it,
    and 1 serial console that is insecure so both BREAK_TO_DEBUGGER
    and ALT_BREAK_TO_DEBUGGER are too insecure to use.  Since they
    are global flags, they must be turned off for all serial consoles.
    Or just don't use multiple serial consoles.  Since no serial console
    drivers support multiple serial consoles, this is too easy to do.

5. Next, the breakage with multiple consoles spread to affect all console
    drivers.  The configuration is now dynamic, with sysctls to control it,
    but the confusion of serial line breaks with breaking into the debugger
    combined with the null support for multiple serial consoles breaks the
    usual case of just no serial consoles at all, as pointed out by jmg.
    The config-time-variable for serial line breaks (BREAK_TO_DEBUGGER) is
    misused to configure "breaking" into the the debugger in the usual ways
    (but not the ways given by ALT_BREAK_TO_DEBUGGER -- that gives security
    holes instead).  From subr_kdb.c:

X #ifdef BREAK_TO_DEBUGGER
X #define	KDB_BREAK_TO_DEBUGGER	1
X #else
X #define	KDB_BREAK_TO_DEBUGGER	0
X #endif

Wrong default for usual entry from non-serial consoles.

X 
X #ifdef ALT_BREAK_TO_DEBUGGER
X #define	KDB_ALT_BREAK_TO_DEBUGGER	1
X #else
X #define	KDB_ALT_BREAK_TO_DEBUGGER	0
X #endif

Better, but it gives security holes for non-serial consoles if it is
configured.

X 
X static int	kdb_break_to_debugger = KDB_BREAK_TO_DEBUGGER;
X static int	kdb_alt_break_to_debugger = KDB_ALT_BREAK_TO_DEBUGGER;
X ...
X SYSCTL_INT(_debug_kdb, OID_AUTO, break_to_debugger,
X     CTLFLAG_RWTUN | CTLFLAG_SECURE,
X     &kdb_break_to_debugger, 0, "Enable break to debugger");
X 
X SYSCTL_INT(_debug_kdb, OID_AUTO, alt_break_to_debugger,
X     CTLFLAG_RWTUN | CTLFLAG_SECURE,
X     &kdb_alt_break_to_debugger, 0, "Enable alternative break to debugger");
X ...
X int
X kdb_break(void)
X {
X 
X 	if (!kdb_break_to_debugger)
X 		return (0);
X 	kdb_enter(KDB_WHY_BREAK, "Break to debugger");
X 	return (KDB_REQ_DEBUGGER);
X }

Only non-alt "breaking" us limited by kdb_break_to_debugger.  kdb_break()
is only called from console drivers:
- from serial console drivers, when a serial line break is received
- from syscons, when the debugger entry key combination is pressed.
   Syscons still has adequate although poorly implemented security for
   this:
   - compile-time configuration by SC_DISABLE_KDBKEY (default enabled)
   - runtime configuration by sysctl hw.syscons.kbd_debug (default from
     the config option)
   The config option shouldn't exist, but the sysctl is needed to handle
   the case of needing kdb_break_to_debugger for a serial console but
   the syscons console being to insecure for this, since the kdb
   sysctl is too global.  This only works since there is really only one
   syscons device -- different security on different vt's is not
   important.
- vt is chummy with the implementation and bypasses some of the
   implementation's bugs by bypassing kdb_break().  So its debugger entry
   in the usual way it is only limited by its own sysctl, like syscons
   used to be.  OTOH, vt doesn't bypass kdb_alt_break() or have its own
   sysctl variable to limit entry in unusual ways.  Syscons uses its old
   SC_DISABLE_KDBKEY+hw.syscons.kbd_debug for this too.

Security holes: GENERIC doesn't have either BREAK_TO_DEBUGGER or
ALT_BREAK_TO_DEBUGGER, so most user configuration probably don't have
either of these either.  Syscons used to default to debugger entry
enabled, but only normal entry was supported.  This was apparently
reversed by the dynamic configuration -- since *BREAK_TO_DEBUGGER is
not the default, the sysctls default to disabled.  Syscons grew support
for alternative "breaking" at much the same time as the dynamic
configuration was added.  Now, if you enable ALT_BREAK_TO_DEBUGGER to
use for a serial console, you get it for syscons and vt too.

My workarounds for this:
- I stopped configuring BREAK_TO_DEBUGGER and started always configuring
   ALT_BREAK_TO_DEBUGGER 10-15 years ago.  Then to fix the reversal of
   the default for debugger keys in syscons:
- in some configurations, I define KDB_BREAK_TO_DEBUGGER as 1
   unconditionally in subr_kdb.c.  I have to remember to either not
   use a serial console or not unplug it.
- in most configurations, I change the sysctl for kdb_break_to_debug
   to 1 early in the boot, and have to remember things as above.  This
   can be confusing.  I forgot that I did this, and was confused by
   ddb working at first when booted with -d, and then later in multi-user
   mode, but not at the askroot prompt or in single user mode.  (The
   debugger and other keys don't work right during the boot, but could
   be made to work better by always checking keys like -p mode does.
   I mainly miss scrollback early, not debugger entry.  Even -p mode is
   affected by multiple console bugs in polled mode.)

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20150526153023.F914>