History

serial/sysrq: Add MAGIC_SYSRQ_SERIAL_SEQUENCE

Many embedded boards have a disconnected TTL level serial which can generate some garbage that can lead to spurious false sysrq detects. Currently, sysrq can be either completely disabled for serial console or always disabled (with CONFIG_MAGIC_SYSRQ_SERIAL), since commit 732dbf3a6104 ("serial: do not accept sysrq characters via serial port") At Arista, we have such boards that can generate BREAK and random garbage. While disabling sysrq for serial console would solve the problem with spurious false sysrq triggers, it's also desirable to have a way to enable sysrq back. As a measure of balance between on and off options, add MAGIC_SYSRQ_SERIAL_SEQUENCE which is a string sequence that can enable sysrq if it follows BREAK on a serial line. The longer the string - the less likely it may be in the garbage. Having the way to enable sysrq was beneficial to debug lockups with a manual investigation in field and on the other side preventing false sysrq detections.

Dmitry Safonov committed 6 years ago

Commit 68af4311 parent eaee4173 files · +77 −7Browse files

Unified · Split

3 files
  1. drivers/tty/serial/serial_core.c +68 −7
  2. include/linux/serial_core.h +1 −0
  3. lib/Kconfig.debug +8 −0
drivers/tty/serial/serial_core.c+68−7
@@ -20,6 +20,7 @@ · 19 unmodified lines
2020 #include <linux/device.h>
2121 #include <linux/serial.h> /* for serial_state and serial_icounter_struct */
2222 #include <linux/serial_core.h>
23+#include <linux/sysrq.h>
2324 #include <linux/delay.h>
2425 #include <linux/mutex.h>
2526 #include <linux/security.h>
@@ -40,6 +41,8 @@ static struct lock_class_key port_lock_key; · 14 unmodified lines
4041
4142 #define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
4243
44+#define SYSRQ_TIMEOUT (HZ * 5)
45+
4346 static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
4447 struct ktermios *old_termios);
4548 static void uart_wait_until_sent(struct tty_struct *tty, int timeout);
@@ -3084,6 +3087,56 @@ void uart_insert_char(struct uart_port *port, unsigned int status, · 3038 unmodified lines
30843087 }
30853088 EXPORT_SYMBOL_GPL(uart_insert_char);
30863089
3090+#ifdef CONFIG_MAGIC_SYSRQ_SERIAL
3091+static const char sysrq_toggle_seq[] = CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE;
3092+
3093+static void uart_sysrq_on(struct work_struct *w)
3094+{
3095+ sysrq_toggle_support(1);
3096+ pr_info("SysRq is enabled by magic sequence on serial\n");
3097+}
3098+static DECLARE_WORK(sysrq_enable_work, uart_sysrq_on);
3099+
3100+/**
3101+ * uart_try_toggle_sysrq - Enables SysRq from serial line
3102+ * @port: uart_port structure where char(s) after BREAK met
3103+ * @ch: new character in the sequence after received BREAK
3104+ *
3105+ * Enables magic SysRq when the required sequence is met on port
3106+ * (see CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE).
3107+ *
3108+ * Returns false if @ch is out of enabling sequence and should be
3109+ * handled some other way, true if @ch was consumed.
3110+ */
3111+static bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
3112+{
3113+ if (ARRAY_SIZE(sysrq_toggle_seq) <= 1)
3114+ return false;
3115+
3116+ BUILD_BUG_ON(ARRAY_SIZE(sysrq_toggle_seq) >= U8_MAX);
3117+ if (sysrq_toggle_seq[port->sysrq_seq] != ch) {
3118+ port->sysrq_seq = 0;
3119+ return false;
3120+ }
3121+
3122+ /* Without the last \0 */
3123+ if (++port->sysrq_seq < (ARRAY_SIZE(sysrq_toggle_seq) - 1)) {
3124+ port->sysrq = jiffies + SYSRQ_TIMEOUT;
3125+ return true;
3126+ }
3127+
3128+ schedule_work(&sysrq_enable_work);
3129+
3130+ port->sysrq = 0;
3131+ return true;
3132+}
3133+#else
3134+static inline bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
3135+{
3136+ return false;
3137+}
3138+#endif
3139+
30873140 int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
30883141 {
30893142 if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL))
@@ -3093,9 +3146,13 @@ int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch) · 3 unmodified lines
30933146 return 0;
30943147
30953148 if (ch && time_before(jiffies, port->sysrq)) {
3096− handle_sysrq(ch);
3097− port->sysrq = 0;
3098− return 1;
3149+ if (sysrq_mask()) {
3150+ handle_sysrq(ch);
3151+ port->sysrq = 0;
3152+ return 1;
3153+ }
3154+ if (uart_try_toggle_sysrq(port, ch))
3155+ return 1;
30993156 }
31003157 port->sysrq = 0;
31013158
@@ -3112,9 +3169,13 @@ int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch) · 10 unmodified lines
31123169 return 0;
31133170
31143171 if (ch && time_before(jiffies, port->sysrq)) {
3115− port->sysrq_ch = ch;
3116− port->sysrq = 0;
3117− return 1;
3172+ if (sysrq_mask()) {
3173+ port->sysrq_ch = ch;
3174+ port->sysrq = 0;
3175+ return 1;
3176+ }
3177+ if (uart_try_toggle_sysrq(port, ch))
3178+ return 1;
31183179 }
31193180 port->sysrq = 0;
31203181
@@ -3154,7 +3215,7 @@ int uart_handle_break(struct uart_port *port) · 33 unmodified lines
31543215 if (port->has_sysrq) {
31553216 if (port->cons && port->cons->index == port->line) {
31563217 if (!port->sysrq) {
3157− port->sysrq = jiffies + HZ*5;
3218+ port->sysrq = jiffies + SYSRQ_TIMEOUT;
31583219 return 1;
31593220 }
31603221 port->sysrq = 0;
include/linux/serial_core.h+1−0
@@ -243,6 +243,7 @@ struct uart_port { · 242 unmodified lines
243243 unsigned long sysrq; /* sysrq timeout */
244244 unsigned int sysrq_ch; /* char for sysrq */
245245 unsigned char has_sysrq;
246+ unsigned char sysrq_seq; /* index in sysrq_toggle_seq */
246247
247248 unsigned char hub6; /* this should be in the 8250 driver */
248249 unsigned char suspended;
lib/Kconfig.debug+8−0
@@ -431,6 +431,14 @@ config MAGIC_SYSRQ_SERIAL · 430 unmodified lines
431431 This option allows you to decide whether you want to enable the
432432 magic SysRq key.
433433
434+config MAGIC_SYSRQ_SERIAL_SEQUENCE
435+ string "Char sequence that enables magic SysRq over serial"
436+ depends on MAGIC_SYSRQ_SERIAL
437+ default ""
438+ help
439+ Specifies a sequence of characters that can follow BREAK to enable
440+ SysRq on a serial console.
441+
434442 config DEBUG_FS
435443 bool "Debug Filesystem"
436444 help

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t