4

I have an extremely bizarre problem, occurring somewhere at the intersection of terminal, su, w3m and /dev/null:

when I su - from user1 to user2, following command does not work:

$ w3m zz.html 2>/dev/null
Error occurred while reset 800b: errno=25

but the same command works fine without the 2>/dev/null redirection:

$ w3m zz.html

And finally, when I login directly as user2 (instead of switching from user1), everything works fine (both with 2>/dev/null and without)

When I run w3m with strace: strace -o zz.strace w3m zz.html 2>/dev/null, I see the two cases (working and non-working) starting to diverge at this point:

ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TCGETS, {B38400 opost isig icanon echo ...}) = 0
ioctl(1, TIOCGWINSZ, {ws_row=77, ws_col=199, ws_xpixel=0, ws_ypixel=0}) = 0
ioctl(2, TIOCGWINSZ, 0x7318fb8e7c40)    = -1 ENOTTY (Inappropriate ioctl for device)
fstat(2, {st_mode=S_IFCHR|0666, st_rdev=makedev(0x1, 0x3), ...}) = 0
ioctl(2, TCGETS, 0x7318fb8e7400)        = -1 ENOTTY (Inappropriate ioctl for device)
brk(0x16a51a8a1000)                     = 0x16a51a8a1000
brk(0x16a51a8b1000)                     = 0x16a51a8b1000
brk(0x16a51a8c2000)                     = 0x16a51a8c2000
brk(0x16a51a8d2000)                     = 0x16a51a8d2000
brk(0x16a51a8e8000)                     = 0x16a51a8e8000
ioctl(2, TCGETS, 0x7318fb8e7bd0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(2, TCGETS, 0x7318fb8e7bc0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(2, SNDCTL_TMR_START or TCSETS, {B0 -opost -isig -icanon -echo ...}) = -1 ENOTTY (Inappropriate ioctl for device)
fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x7), ...}) = 0
write(1, "Error occurred while reset 800b:"..., 42) = 42
write(2, "\33[?1049h\33[22;0;0t\33[H\33[2J\33[39;49m"..., 58) = 58
ioctl(2, TCGETS, 0x7318fb8e7ba0)        = -1 ENOTTY (Inappropriate ioctl for device)
ioctl(2, SNDCTL_TMR_START or TCSETS, {B0 -opost -isig -icanon -echo ...}) = -1 ENOTTY (Inappropriate ioctl for device)
exit_group(1)                           = ?
+++ exited with 1 +++

From what I was able to find, the TIOCGWINSZ ioctl seems to be something related to terminal size. But I am not able to find what exactly is causing this problem.

17
  • I see two attempts to set the options on stderr (file descriptor 2) to something that looks a lot like "raw mode" (B0 -opost -isig -icanon -echo ...). That is 0 bps, no output post-processing, no input control character processing, no echoing of input, etc. This fails, followed by a stat of file descriptor 1, the error message to stdout, some escape sequences that look like xterm ones to stderr, a repeat of the call setting raw mode, and finally exit. What are the differences between the working and non-working strace in the calls: ioctl(2, SNDCTL_TMR_START or TCSETS, {B0 ... ? Commented Oct 22, 2022 at 5:45
  • @Sotto Voce - the non-working is: ioctl(2, SNDCTL_TMR_START or TCSETS, {B0 -opost -isig -icanon -echo ...}) = -1 ENOTTY (Inappropriate ioctl for device), vs the working: ioctl(3, SNDCTL_TMR_START or TCSETS, {B38400 opost -isig -icanon -echo ...}) = 0. I have pasted the full straceses here: ctxt.io/2/AAAQPmMeEQ and ctxt.io/2/AAAQPtNaFg Commented Oct 22, 2022 at 9:43
  • Just for sure... Can you give us the ls -lZ /dev/null output? Commented Oct 24, 2022 at 8:31
  • 1
    @K-att- aha! tty output shows /dev/pts/21 both when run under user1, as well as after i switched to user2 (su - user2). But /dev/pts/21 is owned by user1. Commented Oct 24, 2022 at 11:55
  • 1
    The w3c try to write directly to the console, not to the standard error. Why? Who knows? Commented Oct 24, 2022 at 12:47

1 Answer 1

2
+500

An Update due to comment

Apparently the non-sense with - has been fixed at at Debian. The core of the issue still remains the same - mixing environments.

The issue is the /proc/*/fd/*!

To quote excellent answer from the user1686, don't forget to upvote it, Permission denied on /dev/stderr after sudo.

The core of the issue is:

It's a known quirk of the Linux implementation of /proc; one that never got fixed for many years. With Linux, opening the links under /proc//fd/ doesn't directly duplicate the file descriptor like dup() would (though the magic /proc links could achieve that in theory) – instead it opens the file anew, and will perform a new permission check.

The original post with this issue is from Theodore Tso (from 2008!) - Re: RFC: /dev/stdin, symlinks & permissions

The solution

Is to get new pty for the userB:

userA:~$ su -l -P userB

From the man pages of su:

   -, -l, --login
       Start the shell as a login shell with an environment similar to a real login:

       •   clears all the environment variables except TERM and variables specified by
           --whitelist-environment

       •   initializes the environment variables HOME, SHELL, USER, LOGNAME, and PATH

       •   changes to the target user’s home directory

   -P, --pty
       Create a pseudo-terminal for the session. The independent terminal provides better
       security as the user does not share a terminal with the original session. This can be
       used to avoid TIOCSTI ioctl terminal injection and other security attacks against
       terminal file descriptors. The entire session can also be moved to the background
       (e.g., su --pty - username -c application &). If the pseudo-terminal is enabled, then
       su works as a proxy between the sessions (sync stdin and stdout).

       This feature is mostly designed for interactive sessions. If the standard input is not
       a terminal, but for example a pipe (e.g., echo "date" | su --pty), then the ECHO flag

I had a chance to test it on Debian Bookworm and it works:

ghu@magnetron:/tmp$ w3m testing.html 2>/dev/null
Error occurred while reset 800b: errno=25
ughu@magnetron:/tmp$ exit
logout
tukan@magnetron:~/Downloads/html$ su -l -P ughu
Password: 
ughu@magnetron:~$ cd /tmp
ughu@magnetron:/tmp$ w3m testing.html 2>/dev/null
ughu@magnetron:/tmp$ exit

Edit based on the OP discussion

The difference between OP and my version (2.33.1-0.1 vs 2.38.1-1.1+b1 - here is the complete changelog).

The OP has discovered that stderr redirect works if it is short enough even with simple su -. For example, this works - execute in shell non-existing-command 2>/dev/null or non-existing-command 2>/tmp/output.

On the other hand, if the output is too long (There is most likely a reset at ~2^15 (32768) bytes indicated by the error message hex: 800b which is dec: 32768+0+0+11) like in a case of w3m application there is a reset done and the user rights are checked again and it fails.

Some patch, which exactly I don't know, fixed the issue between the util-linux version 2.33.1-0.1 and 2.38.1-1.1+b1.

Conclusion

You need to use the newer version (I don't from which version it works), but in my case the 2.38.1-1.1+b1 with the -P switch was working correctly. The redirect will then work even for large output from w3m as I have show above.

9
  • I am using su on Debian 10, and my man page lists options -, -l, --login as identical. And when I use su --login instead of su -, the problem remains the same. Commented Oct 25, 2022 at 3:45
  • 1
    @400theCat Ok, they probably fixed this nonsense (from when I have encountered it years ago), but you are, on 99.9%, suffering from the side effects of mixed environments. I'll edit the answer when I find more about it. Commented Oct 25, 2022 at 7:49
  • thank you, but su -l -P does not solve it for me. I have still the same problem Commented Oct 25, 2022 at 14:30
  • @400theCat What version of su resp. util-linux do you have? As I have shown above on Debian Bookworm and bash it works. That is copy&paste from ny terminal. Commented Oct 25, 2022 at 16:39
  • I am on Debian 10 and my util-linux is version 2.33.1-0.1 Commented Oct 25, 2022 at 16:54

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.