1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (c) 2018 Google, Inc. 4 */ 5 6/* 7 * Regression test for commit 966031f340185 ("n_tty: fix EXTPROC vs ICANON 8 * interaction with TIOCINQ (aka FIONREAD)"). The test reproduces a hang 9 * (infinite loop in the kernel) after a pseudoterminal is put in both canonical 10 * (ICANON) and external processing (EXTPROC) mode, some data is written to the 11 * master and read from the slave, and the FIONREAD ioctl is called on the 12 * slave. This is simplified from a syzkaller-generated reproducer. 13 */ 14 15#define _GNU_SOURCE 16#include <stdlib.h> 17#include <errno.h> 18#include <sys/ioctl.h> 19#include <termios.h> 20 21#include "tst_test.h" 22#include "lapi/termbits.h" 23 24static void do_test(void) 25{ 26 struct termios io; 27 int ptmx, pts; 28 char c = 'A'; 29 int nbytes; 30 31 ptmx = SAFE_OPEN("/dev/ptmx", O_WRONLY); 32 33 if (tcgetattr(ptmx, &io) != 0) 34 tst_brk(TBROK | TERRNO, "tcgetattr() failed"); 35 36 io.c_lflag = EXTPROC | ICANON; 37 38 TEST(tcsetattr(ptmx, TCSANOW, &io)); 39 if (TST_RET == -1) { 40 if (TST_ERR == EINVAL) 41 tst_brk(TCONF, "tcsetattr(, , EXTPROC | ICANON) is not supported"); 42 tst_brk(TBROK | TTERRNO, "tcsetattr() failed"); 43 } 44 45 if (unlockpt(ptmx) != 0) 46 tst_brk(TBROK | TERRNO, "unlockpt() failed"); 47 48 pts = SAFE_OPEN(ptsname(ptmx), O_RDONLY); 49 /* write newline to ptmx to avoid read() on pts to block */ 50 SAFE_WRITE(SAFE_WRITE_ALL, ptmx, "A\n", 2); 51 SAFE_READ(1, pts, &c, 1); 52 53 tst_res(TINFO, "Calling FIONREAD, this will hang in n_tty_ioctl() if the bug is present..."); 54 SAFE_IOCTL(pts, FIONREAD, &nbytes); 55 56 SAFE_CLOSE(ptmx); 57 SAFE_CLOSE(pts); 58 59 tst_res(TPASS, "Got to the end without hanging"); 60} 61 62static struct tst_test test = { 63 .test_all = do_test, 64 .tags = (const struct tst_tag[]) { 65 {"linux-git", "966031f34018"}, 66 {} 67 } 68}; 69