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.

400 the Cat
  • 819
  • 4
  • 37
  • 85
  • 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 ...` ? – Sotto Voce Oct 22 '22 at 05: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: https://ctxt.io/2/AAAQPmMeEQ and https://ctxt.io/2/AAAQPtNaFg – 400 the Cat Oct 22 '22 at 09:43
  • Just for sure... Can you give us the `ls -lZ /dev/null` output? – K-attila- Oct 24 '22 at 08:31
  • @K-att- `crw-rw-rw- 1 root root ? 1, 3 Oct 23 09:25 /dev/null` – 400 the Cat Oct 24 '22 at 08:57
  • It seems to be ok. Stderr is stream and the /dev/null character device, but what is the different in user1 and user2? Can you try the su without -? – K-attila- Oct 24 '22 at 09:20
  • @K-att- te problem is the same, irrespective of whether I use `su user2` or `su - user2` – 400 the Cat Oct 24 '22 at 09:34
  • The good : `fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x13), ...}) = 0 readlink("/proc/self/fd/0", "/dev/pts/19", 4095) = 11 stat("/dev/pts/19", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x13), ...}) = 0 openat(AT_FDCWD, "/dev/pts/19", O_RDWR) = 3 fcntl(3, F_GETFL) = 0x8002 (flags O_RDWR|O_LARGEFILE)` And the bad: – K-attila- Oct 24 '22 at 10:56
  • `fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x14), ...}) = 0 readlink("/proc/self/fd/0", "/dev/pts/20", 4095) = 11 stat("/dev/pts/20", {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x14), ...}) = 0 openat(AT_FDCWD, "/dev/pts/20", O_RDWR) = -1 EACCES (Permission denied) fcntl(2, F_GETFL) = 0x8001 (flags O_WRONLY|O_LARGEFILE)` – K-attila- Oct 24 '22 at 10:58
  • Can you tell us the `tty` output before and after su? I think it is `/dev/pts/19' both. => the w3c use wrong pseudo terminal. – K-attila- Oct 24 '22 at 11:33
  • 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`. – 400 the Cat Oct 24 '22 at 11:47
  • 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`. – 400 the Cat Oct 24 '22 at 11:55
  • Check it. If you switch to user2, the w3c try which pseudo terminal? – K-attila- Oct 24 '22 at 12:15
  • @K-att- as I said, if I switch to `user2`, then `w3m` tires to use `/dev/pts/21` which is owned by the original `user1` – 400 the Cat Oct 24 '22 at 12:19
  • Then we know what happened :). Ad acta. – K-attila- Oct 24 '22 at 12:31
  • @K-att- so how do i fix this problem ? Why is it happening? – 400 the Cat Oct 24 '22 at 12:34
  • Sorry, I don't want to check the w3c source code yet. – K-attila- Oct 24 '22 at 12:40
  • 1
    The w3c try to write directly to the console, not to the standard error. Why? Who knows? – K-attila- Oct 24 '22 at 12:47

1 Answers1

2

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.

tukan
  • 4,876
  • 6
  • 19
  • 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. – 400 the Cat Oct 25 '22 at 03: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. – tukan Oct 25 '22 at 07:49
  • thank you, but `su -l -P ` does not solve it for me. I have still the same problem – 400 the Cat Oct 25 '22 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. – tukan Oct 25 '22 at 16:39
  • I am on Debian 10 and my `util-linux` is version `2.33.1-0.1` – 400 the Cat Oct 25 '22 at 16:54
  • I have different version of `util-linux`: `2.38.1-1.1+b1` I think it is to move to chat - https://chat.stackoverflow.com/rooms/249065/room-for-tukan-and-400-the-cat . – tukan Oct 26 '22 at 08:34
  • @400theCat I have added information based on our discussion in the chat room. – tukan Oct 27 '22 at 10:18
  • @tukan Bravo. It was great. – K-attila- Oct 27 '22 at 10:46
  • @K-att- thank you, it helped to have communication with OP – tukan Oct 27 '22 at 11:41