* more(1) may attempt to tcsetattr(3) despite lacking controlling terminal
@ 2016-10-13 14:39 Jan Schaumann
2016-10-13 19:14 ` Bruce Dubbs
2016-10-19 10:09 ` Karel Zak
0 siblings, 2 replies; 7+ messages in thread
From: Jan Schaumann @ 2016-10-13 14:39 UTC (permalink / raw)
To: util-linux-ng
Hello,
Yesterday I reported the following bug to the Debian maintainers of the
'util-linux' package. They suggested I should bring it up here:
more(1) may attempt to call tsetattr(3) on stderr even if its process is
not in a process group with a controlling terminal. As a result,
SIGTTOU will be generated, suspending the process.
The following example illustrates the issue:
$ /bin/sh -c "timeout 60 /bin/sh -c \"ls | more\""
This command will now hang until the timeout, since the shell, ls(1) and
more(1) commands invoked by timeout(1) will be suspended.
Note the difference to
$ timeout 60 /bin/sh -c "ls | more"
which behaves as expected, since here the entire shell command is in the
process group that has the controlling terminal.
Now regardless of whether or not timeout(1) properly sets up the
terminal or process groups, it seems to me that more(1) should not
attempt to manipulate the terminal when it is not in the process group
with the controlling terminal.
As I see it,tThe problem is in text-utils/more.c, where a call to
tcsetattr(3) is made on stderr. The test for whether or not a tty is
present is not sufficient here, since a tty may be present but not be in
the process group of the controlling terminal.
A simplified PoC of the problematic code looks like this:
--- 8< --------- 8< --------- 8< ---------
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int
main(int argc, char ** argv) {
struct termios otty;
int no_tty;
if (setpgid(0, 0) == -1) {
fprintf(stderr, "Unable to setpgid: %s\n", strerror(errno));
exit(1);
}
no_tty = tcgetattr(fileno(stdout), &otty);
if (!no_tty) {
#ifdef FIX
if (tcgetpgrp(fileno(stderr)) == getpgrp()) {
#endif
if (tcsetattr(fileno(stderr), TCSANOW, &otty) == -1) {
fprintf(stderr, "Unable to tcsetattr: %s\n", strerror(errno));
exit(1);
}
#ifdef FIX
}
#endif
}
return 0;
}
--- 8< --------- 8< --------- 8< ---------
If compiled without '-DFIX', then we observe the following:
$ ./a.out
$ /bin/sh -c ./a.out
[hangs, can't ^C, need to suspend and kill]
If compiled with '-DFIX', we get the desired behaviour.
The fix to text-utils/more.c should then be:
--- 8< --------- 8< --------- 8< ---------
--- more.c 2016-10-12 18:19:00.858761448 -0400
+++ more.c.orig 2011-09-26 05:50:25.000000000 -0400
@@ -1769,16 +1769,6 @@
retry:
#endif /* do_SIGTTOU */
no_tty = tcgetattr(fileno(stdout), &otty);
- no_intty = tcgetattr(fileno(stdin), &otty);
-
- /* If we are not in the process group with the controlling terminal,
- * then we have on business trying to interact with it, so let's
- * pretend there isn't a tty. */
- if (tcgetpgrp(fileno(stdout)) != getpgrp()) {
- no_tty = 1;
- no_intty = 1;
- }
-
if (!no_tty) {
docrterase = (otty.c_cc[VERASE] != 255);
docrtkill = (otty.c_cc[VKILL] != 255);
@@ -1880,7 +1870,7 @@
if ((shell = getenv("SHELL")) == NULL)
shell = "/bin/sh";
}
-
+ no_intty = tcgetattr(fileno(stdin), &otty);
tcgetattr(fileno(stderr), &otty);
savetty0 = otty;
slow_tty = cfgetispeed(&otty) < B1200;
--- 8< --------- 8< --------- 8< ---------
That is, if the current process group is not the same as the process
group of the controlling terminal, then it's best to pretend that we
don't have a terminal and cause more(1) to merely copy the input rather
than attempt to paginate.
-Jan
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: more(1) may attempt to tcsetattr(3) despite lacking controlling terminal
2016-10-13 14:39 more(1) may attempt to tcsetattr(3) despite lacking controlling terminal Jan Schaumann
@ 2016-10-13 19:14 ` Bruce Dubbs
2016-10-13 20:18 ` Jakob Unterwurzacher
2016-10-19 10:09 ` Karel Zak
1 sibling, 1 reply; 7+ messages in thread
From: Bruce Dubbs @ 2016-10-13 19:14 UTC (permalink / raw)
To: Jan Schaumann, util-linux-ng
Jan Schaumann wrote:
> Hello,
>
> Yesterday I reported the following bug to the Debian maintainers of the
> 'util-linux' package. They suggested I should bring it up here:
>
>
> more(1) may attempt to call tsetattr(3) on stderr even if its process is
> not in a process group with a controlling terminal. As a result,
> SIGTTOU will be generated, suspending the process.
>
> The following example illustrates the issue:
>
> $ /bin/sh -c "timeout 60 /bin/sh -c \"ls | more\""
>
> This command will now hang until the timeout, since the shell, ls(1) and
> more(1) commands invoked by timeout(1) will be suspended.
It does not hang for me, but then I don't use systemd. Perhaps systemd
should be fixed.
-- Bruce
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: more(1) may attempt to tcsetattr(3) despite lacking controlling terminal
2016-10-13 19:14 ` Bruce Dubbs
@ 2016-10-13 20:18 ` Jakob Unterwurzacher
2016-10-13 20:52 ` Bruce Dubbs
0 siblings, 1 reply; 7+ messages in thread
From: Jakob Unterwurzacher @ 2016-10-13 20:18 UTC (permalink / raw)
To: util-linux-ng
On 13.10.2016 21:14, Bruce Dubbs wrote:
>>
>> The following example illustrates the issue:
>>
>> $ /bin/sh -c "timeout 60 /bin/sh -c \"ls | more\""
>>
>> This command will now hang until the timeout, since the shell, ls(1) and
>> more(1) commands invoked by timeout(1) will be suspended.
>
> It does not hang for me, but then I don't use systemd. Perhaps systemd should
> be fixed.
Does not hang for me either on Fedora 24, and I am using systemd, but how is
this related to the init system
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: more(1) may attempt to tcsetattr(3) despite lacking controlling terminal
2016-10-13 20:18 ` Jakob Unterwurzacher
@ 2016-10-13 20:52 ` Bruce Dubbs
2016-10-19 9:53 ` Karel Zak
0 siblings, 1 reply; 7+ messages in thread
From: Bruce Dubbs @ 2016-10-13 20:52 UTC (permalink / raw)
To: Jakob Unterwurzacher, util-linux-ng
Jakob Unterwurzacher wrote:
> On 13.10.2016 21:14, Bruce Dubbs wrote:
>>>
>>> The following example illustrates the issue:
>>>
>>> $ /bin/sh -c "timeout 60 /bin/sh -c \"ls | more\""
>>>
>>> This command will now hang until the timeout, since the shell, ls(1) and
>>> more(1) commands invoked by timeout(1) will be suspended.
>>
>> It does not hang for me, but then I don't use systemd. Perhaps systemd should
>> be fixed.
>
> Does not hang for me either on Fedora 24, and I am using systemd, but how is
> this related to the init system
If systemd was only an init system, I wouldn't object. It has subsumed
much more than initialization, e.g udev, dhcp client, managing cgroups,
'seat management', etc. My initial reaction to the original problem is
that it is cgroups related.
-- Bruce
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: more(1) may attempt to tcsetattr(3) despite lacking controlling terminal
2016-10-13 20:52 ` Bruce Dubbs
@ 2016-10-19 9:53 ` Karel Zak
0 siblings, 0 replies; 7+ messages in thread
From: Karel Zak @ 2016-10-19 9:53 UTC (permalink / raw)
To: Bruce Dubbs; +Cc: Jakob Unterwurzacher, util-linux-ng
On Thu, Oct 13, 2016 at 03:52:33PM -0500, Bruce Dubbs wrote:
> Jakob Unterwurzacher wrote:
> > On 13.10.2016 21:14, Bruce Dubbs wrote:
> > > >
> > > > The following example illustrates the issue:
> > > >
> > > > $ /bin/sh -c "timeout 60 /bin/sh -c \"ls | more\""
> > > >
> > > > This command will now hang until the timeout, since the shell, ls(1) and
> > > > more(1) commands invoked by timeout(1) will be suspended.
I'm not able to reproduce this problem too.
> > > It does not hang for me, but then I don't use systemd. Perhaps systemd should
> > > be fixed.
I have systemd.
> > Does not hang for me either on Fedora 24, and I am using systemd, but how is
> > this related to the init system
>
> If systemd was only an init system, I wouldn't object. It has subsumed much
> more than initialization, e.g udev, dhcp client, managing cgroups, 'seat
> management', etc. My initial reaction to the original problem is that it is
> cgroups related.
Probably no, the question is where is the problem.
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: more(1) may attempt to tcsetattr(3) despite lacking controlling terminal
2016-10-13 14:39 more(1) may attempt to tcsetattr(3) despite lacking controlling terminal Jan Schaumann
2016-10-13 19:14 ` Bruce Dubbs
@ 2016-10-19 10:09 ` Karel Zak
2016-10-20 14:56 ` Sami Kerola
1 sibling, 1 reply; 7+ messages in thread
From: Karel Zak @ 2016-10-19 10:09 UTC (permalink / raw)
To: Jan Schaumann; +Cc: util-linux-ng, Sami Kerola
On Thu, Oct 13, 2016 at 10:39:32AM -0400, Jan Schaumann wrote:
> more(1) may attempt to call tsetattr(3) on stderr even if its process is
> not in a process group with a controlling terminal. As a result,
> SIGTTOU will be generated, suspending the process.
Frankly, all the code:
tcgetattr(fileno(stderr), &otty);
savetty0 = otty;
slow_tty = cfgetispeed(&otty) < B1200;
hardtabs = (otty.c_oflag & TABDLY) != XTABS;
seems strange, it does not care if the tcgetattr() has been successful
on stderr, etc.
ls | more 2> /dev/null
behaves differently than without stderr redirection.
All the code is pretty mess (e.g. slow_tty is nowhere used, etc.).
Sami has tried to cleanup the code, but not sure about status of this
project (https://github.com/kerolasa/lelux-utiliteetit/commits/more3).
Karel
--
Karel Zak <kzak@redhat.com>
http://karelzak.blogspot.com
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: more(1) may attempt to tcsetattr(3) despite lacking controlling terminal
2016-10-19 10:09 ` Karel Zak
@ 2016-10-20 14:56 ` Sami Kerola
0 siblings, 0 replies; 7+ messages in thread
From: Sami Kerola @ 2016-10-20 14:56 UTC (permalink / raw)
To: Karel Zak; +Cc: Jan Schaumann, util-linux-ng
On 19 October 2016 at 11:09, Karel Zak <kzak@redhat.com> wrote:
> On Thu, Oct 13, 2016 at 10:39:32AM -0400, Jan Schaumann wrote:
>> more(1) may attempt to call tsetattr(3) on stderr even if its process is
>> not in a process group with a controlling terminal. As a result,
>> SIGTTOU will be generated, suspending the process.
>
> Frankly, all the code:
>
> tcgetattr(fileno(stderr), &otty);
> savetty0 = otty;
> slow_tty = cfgetispeed(&otty) < B1200;
> hardtabs = (otty.c_oflag & TABDLY) != XTABS;
>
> seems strange, it does not care if the tcgetattr() has been successful
> on stderr, etc.
>
> ls | more 2> /dev/null
>
> behaves differently than without stderr redirection.
>
> All the code is pretty mess (e.g. slow_tty is nowhere used, etc.).
> Sami has tried to cleanup the code, but not sure about status of this
> project (https://github.com/kerolasa/lelux-utiliteetit/commits/more3).
I do not know how to test more(1) automatically, so sending long
pull with zillion changes cannot be accepted.
--
Sami Kerola
http://www.iki.fi/kerolasa/
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2016-10-20 14:56 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-10-13 14:39 more(1) may attempt to tcsetattr(3) despite lacking controlling terminal Jan Schaumann
2016-10-13 19:14 ` Bruce Dubbs
2016-10-13 20:18 ` Jakob Unterwurzacher
2016-10-13 20:52 ` Bruce Dubbs
2016-10-19 9:53 ` Karel Zak
2016-10-19 10:09 ` Karel Zak
2016-10-20 14:56 ` Sami Kerola
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.