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
20#include <linux/device.h>20#include <linux/device.h>
21#include <linux/serial.h> /* for serial_state and serial_icounter_struct */21#include <linux/serial.h> /* for serial_state and serial_icounter_struct */
22#include <linux/serial_core.h>22#include <linux/serial_core.h>
23#include <linux/sysrq.h>
23#include <linux/delay.h>24#include <linux/delay.h>
24#include <linux/mutex.h>25#include <linux/mutex.h>
25#include <linux/security.h>26#include <linux/security.h>
@@ -40,6 +41,8 @@ static struct lock_class_key port_lock_key; · 14 unmodified lines
40 41
41#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)42#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
42 43
44#define SYSRQ_TIMEOUT (HZ * 5)
45
43static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,46static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
44 struct ktermios *old_termios);47 struct ktermios *old_termios);
45static void uart_wait_until_sent(struct tty_struct *tty, int timeout);48static 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
3084}3087}
3085EXPORT_SYMBOL_GPL(uart_insert_char);3088EXPORT_SYMBOL_GPL(uart_insert_char);
3086 3089
3090#ifdef CONFIG_MAGIC_SYSRQ_SERIAL
3091static const char sysrq_toggle_seq[] = CONFIG_MAGIC_SYSRQ_SERIAL_SEQUENCE;
3092
3093static 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}
3098static 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 */
3111static 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
3134static inline bool uart_try_toggle_sysrq(struct uart_port *port, unsigned int ch)
3135{
3136 return false;
3137}
3138#endif
3139
3087int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)3140int uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
3088{3141{
3089 if (!IS_ENABLED(CONFIG_MAGIC_SYSRQ_SERIAL))3142 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
3093 return 0;3146 return 0;
3094 3147
3095 if (ch && time_before(jiffies, port->sysrq)) {3148 if (ch && time_before(jiffies, port->sysrq)) {
3096 handle_sysrq(ch);3149 if (sysrq_mask()) {
3097 port->sysrq = 0;3150 handle_sysrq(ch);
3098 return 1;3151 port->sysrq = 0;
3152 return 1;
3153 }
3154 if (uart_try_toggle_sysrq(port, ch))
3155 return 1;
3099 }3156 }
3100 port->sysrq = 0;3157 port->sysrq = 0;
3101 3158
@@ -3112,9 +3169,13 @@ int uart_prepare_sysrq_char(struct uart_port *port, unsigned int ch) · 10 unmodified lines
3112 return 0;3169 return 0;
3113 3170
3114 if (ch && time_before(jiffies, port->sysrq)) {3171 if (ch && time_before(jiffies, port->sysrq)) {
3115 port->sysrq_ch = ch;3172 if (sysrq_mask()) {
3116 port->sysrq = 0;3173 port->sysrq_ch = ch;
3117 return 1;3174 port->sysrq = 0;
3175 return 1;
3176 }
3177 if (uart_try_toggle_sysrq(port, ch))
3178 return 1;
3118 }3179 }
3119 port->sysrq = 0;3180 port->sysrq = 0;
3120 3181
@@ -3154,7 +3215,7 @@ int uart_handle_break(struct uart_port *port) · 33 unmodified lines
3154 if (port->has_sysrq) {3215 if (port->has_sysrq) {
3155 if (port->cons && port->cons->index == port->line) {3216 if (port->cons && port->cons->index == port->line) {
3156 if (!port->sysrq) {3217 if (!port->sysrq) {
3157 port->sysrq = jiffies + HZ*5;3218 port->sysrq = jiffies + SYSRQ_TIMEOUT;
3158 return 1;3219 return 1;
3159 }3220 }
3160 port->sysrq = 0;3221 port->sysrq = 0;
include/linux/serial_core.h+1−0
@@ -243,6 +243,7 @@ struct uart_port { · 242 unmodified lines
243 unsigned long sysrq; /* sysrq timeout */243 unsigned long sysrq; /* sysrq timeout */
244 unsigned int sysrq_ch; /* char for sysrq */244 unsigned int sysrq_ch; /* char for sysrq */
245 unsigned char has_sysrq;245 unsigned char has_sysrq;
246 unsigned char sysrq_seq; /* index in sysrq_toggle_seq */
246 247
247 unsigned char hub6; /* this should be in the 8250 driver */248 unsigned char hub6; /* this should be in the 8250 driver */
248 unsigned char suspended;249 unsigned char suspended;
lib/Kconfig.debug+8−0
@@ -431,6 +431,14 @@ config MAGIC_SYSRQ_SERIAL · 430 unmodified lines
431 This option allows you to decide whether you want to enable the431 This option allows you to decide whether you want to enable the
432 magic SysRq key.432 magic SysRq key.
433 433
434config 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
434config DEBUG_FS442config DEBUG_FS
435 bool "Debug Filesystem"443 bool "Debug Filesystem"
436 help444 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