-
Bug
-
Resolution: Unresolved
-
Normal
-
None
-
rhel-8.7.0, rhel-9.2.0, rhel-10.0
-
None
-
Moderate
-
rhel-sst-cs-plumbers
-
ssg_core_services
-
5
-
False
-
-
None
-
None
-
None
-
None
-
If docs needed, set a value
-
-
All
-
None
Description of problem:
When sudo is configured with "Defaults use_pty", executing the following command from a ksh shell breaks ksh:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
$ sudo -u root echo hello|head -1
[sudo] password for kshuser:
hello
$
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
At the prompt, which is also not properly printed (should be at beginning of the line), typing keys shows nothing, because the terminal remains in "noecho" mode forever.
The root cause for this is "sudo" fails to restore the "echo" mode, due to getting SIGTTOU:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
32666 15:26:03.848421 ioctl(4</dev/tty<char 5:0>>, SNDCTL_TMR_STOP or TCSETSW,
) = ? ERESTARTSYS (To be restarted if SA_RESTART is set) <0.000007>
32666 15:26:03.848448 — SIGTTOU
—
32666 15:26:03.848458 rt_sigreturn(
) = -1 EINTR (Interrupted system call) <0.000003>
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
Corresponding "sudo" source code is:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
119 static int
120 tcsetattr_nobg(int fd, int flags, struct termios *tp)
121 {
122 struct sigaction sa, osa;
123 int rc;
124
125 /*
126 * If we receive SIGTTOU from tcsetattr() it means we are
127 * not in the foreground process group.
128 * This should be less racy than using tcgetpgrp().
129 */
130 memset(&sa, 0, sizeof(sa));
131 sigemptyset(&sa.sa_mask);
132 sa.sa_handler = sigttou;
133 got_sigttou = 0;
134 sigaction(SIGTTOU, &sa, &osa);
135 do
while (rc != 0 && errno == EINTR && !got_sigttou);
138 sigaction(SIGTTOU, &osa, NULL);
139
140 return rc;
141 }
147 bool
148 sudo_term_restore_v1(int fd, bool flush)
149 {
150 debug_decl(sudo_term_restore, SUDO_DEBUG_UTIL)
151
152 if (changed)
158 debug_return_bool(true);
159 }
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
Here above on line 154, the call fails because tcsetattr_nobg() gets SIGTTOU signal.
This happens because "sudo" is not the foreground process anymore, it's "ksh" which took over already:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
32627 15:26:03.847559 ioctl(2</dev/pts/1<char 136:1>>, TIOCGPGRP <unfinished ...>
32627 15:26:03.847584 <... ioctl resumed>, [32666]) = 0 <0.000013>
--> here 32666 is "sudo", which makes "ksh" take over foreground:
32627 15:26:03.847604 ioctl(2</dev/pts/1<char 136:1>>, TIOCSPGRP, [32627] <unfinished ...>
32627 15:26:03.847627 <... ioctl resumed>) = 0 <0.000012>
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
We can see using a stap script that "ksh" gets back to foreground while waiting for "sudo" to exit:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
32725 (ksh) calling ioctl(TIOCSPGRP)
0x7fb819f127cb : ioctl+0xb/0x30 [/usr/lib64/libc-2.28.so]
0x7fb819fff48d : tcsetpgrp+0x1d/0x30 [/usr/lib64/libc-2.28.so]
0x56259cc8778a : job_reset+0x9a/0xc0 [/usr/bin/ksh93]
0x56259cc8965c : job_wait+0x30c/0x8a0 [/usr/bin/ksh93]
0x56259ccbe70a : sh_exec+0x424a/0x5cf0 [/usr/bin/ksh93]
0x56259ccbd880 : sh_exec+0x33c0/0x5cf0 [/usr/bin/ksh93]
0x56259cc66327 : exfile+0x977/0xcd0 [/usr/bin/ksh93]
0x56259cc66c3c : sh_main+0x36c/0x930 [/usr/bin/ksh93]
0x7fb819f13d85 : __libc_start_main+0xe5/0x180 [/usr/lib64/libc-2.28.so]
0x56259cc658ee : _start+0x2e/0x30 [/usr/bin/ksh93]
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
Which is the following "ksh" code:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
1486 int job_wait(register pid_t pid)
1487 {
:
1549 while(1)
1550 {
:
1631 }
:
1641 if(pw->p_pgrp)
1642 {
1643 job_reset(pw);
:
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
Delaying line 1643 until sudo really completed shows terminal is functional again.
It looks like to me the "while(1)" block (lines 1549-1631) is not waiting for all jobs to complete.
I can see using gdb that the block exits because "ksh" monitors "head" which exits before "sudo":
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
(gdb) break jobs.c:1614
Breakpoint 2 at 0x55db5ac8e5fc: file /usr/src/debug/ksh-20120801-257.el8.x86_64/src/cmd/ksh93/sh/jobs.c, line 1614.
(gdb) cont
Breakpoint 2, job_wait (pid=34776) at /usr/src/debug/ksh-20120801-257.el8.x86_64/src/cmd/ksh93/sh/jobs.c:1614
1614 if(!px || !job.waitall)
(gdb) p pw->p_pid
$3 = 34776
(gdb) p pw->p_nxtproc
$4 = (struct process *) 0x7f4b95ec1a60
(gdb) p pw->p_nxtproc->p_pid
$5 = 34775
(gdb) p job.waitall
$6 = 0 '\000'
-------- 8< ---------------- 8< ---------------- 8< ---------------- 8< --------
Because we don't have "job.waitall", we exit the block and "hijack" the terminal through going foreground again, without letting "sudo" restore the settings.
Version-Release number of selected component (if applicable):
ksh-20120801-257.el8
sudo-1.8.29-8.el8_7.1
How reproducible:
Always
Steps to Reproduce:
1. Add "Defaults use_pty" in /etc/sudoers
2. As a KSH user, execute the above command