You are not logged in.

#1 2023-01-23 00:29:24

hexadecagram
Member
Registered: 2011-05-20
Posts: 61

Permissions issue involving zsh, mktemp, and tar

This definitely seems to be a permissions issue. If I don't use sudo, it works fine. Same behavior with and without parentheses. Any thoughts what could be causing this?

$ mount | grep /tmp
tmpfs on /tmp type tmpfs (rw,nosuid,nodev,size=16379884k,nr_inodes=1048576,inode64)
$ stat -c %a /tmp
1777
$ (
  t=$(mktemp)
  trap "{ rm -f $t; }" EXIT
  chmod 666 $t
  sudo tar cf $t -C anydir anyfiles
  sudo tar rf $t -C anydir anyfiles
  tar tvf $t
)
tar: /tmp/tmp.vpDEuGmWFj: Cannot open: Permission denied
tar: Error is not recoverable: exiting now
tar: /tmp/tmp.vpDEuGmWFj: Cannot read: Bad file descriptor
tar: At beginning of tape, quitting now
tar: Error is not recoverable: exiting now
tar: This does not look like a tar archive
tar: Exiting with failure status due to previous errors

Offline

#2 2023-01-23 01:31:12

hexadecagram
Member
Registered: 2011-05-20
Posts: 61

Re: Permissions issue involving zsh, mktemp, and tar

Found my solution!

$ (
  t=$(mktemp -u)
  trap "{ sudo rm -f $t; }" EXIT
  sudo tar cf $t -C anydir anyfiles
  sudo tar rf $t -C anydir anyfiles
  tar tvf $t
)

The closest explanation I can think of can be found in chmod(1), but unless I'm misunderstanding, it doesn't explain why a privileged user cannot overwrite a file in sticky /tmp. Any other ideas?

RESTRICTED DELETION FLAG OR STICKY BIT
       The restricted deletion flag or sticky bit is a single bit, whose interpretation depends on the file type. For directories, it prevents unprivileged users from removing or renaming a file in the directory unless they own the file or the directory; this is called the restricted deletion flag for the directory, and is commonly found on world-writable directories like /tmp. For regular files on some older systems, the bit saves the program's text image on the swap device so it will load more quickly when run; this is called the sticky bit.

Last edited by hexadecagram (2023-01-23 01:32:09)

Offline

#3 2023-01-23 09:33:05

seth
Member
Registered: 2012-09-03
Posts: 35,274

Re: Permissions issue involving zsh, mktemp, and tar

The problem is that you're trying to add a restricted file to an unrestricted archive

cd /tmp
touch test.tar
sudo tar cf test.tar /etc/shadow # error
sudo chown root:root test.tar
sudo tar cf test.tar /etc/shadow # "tar-dar"…

Offline

#4 2023-01-24 17:26:39

hexadecagram
Member
Registered: 2011-05-20
Posts: 61

Re: Permissions issue involving zsh, mktemp, and tar

Hmm, there's the following also. In short, GNU tar and bsdtar behave differently in this context.

$ (
  t=$(mktemp)
  trap "{ sudo rm -f $t; }" EXIT
  sudo bsdtar cf $t /etc/shadow # likewise error
  bsdtar tvf $t
)
bsdtar: Failed to open '/tmp/tmp.vSJo4qQxqO'
$ (
  t=$(mktemp)
  trap "{ sudo rm -f $t; }" EXIT
  sudo chown root:root $t # chown but no "tar-dar"; GNU tar works, bsdtar doesn't!
  sudo bsdtar cf $t /etc/shadow
  bsdtar tvf $t
)
bsdtar: Removing leading '/' from member names
bsdtar: Error opening archive: Failed to open '/tmp/tmp.iHaVtnJFwx'
$ (
  t=$(mktemp -u) # works because temp file is not actually created; $t is just assigned a value
  trap "{ sudo rm -f $t; }" EXIT
  sudo bsdtar cf $t /etc/shadow
  bsdtar tvf $t
)
bsdtar: Removing leading '/' from member names
-rw-------  0 root   root      912 Oct 21 16:23 etc/shadow

To me, it still seems like an undocumented "feature" of the sticky bit or something else to do with the filesystem, perhaps evidenced by this:

$ touch /tmp/testfile
$ echo hello | sudo tee /tmp/testfile > /dev/null
tee: /tmp/testfile: Permission denied
$ cat /tmp/testfile # no output because elevated write to user-owned file in /tmp fails
$ sudo chown root:root /tmp/testfile
$ echo hello | sudo tee /tmp/testfile > /dev/null
$ cat /tmp/testfile # elevated write to root-owned file succeeds
hello
$ stat -c %a ~ # no sticky bit on ~
700
$ touch ~/testfile
$ echo hello | sudo tee ~/testfile > /dev/null
$ cat ~/testfile # elevated write to user-owned file in ~ succeeds
hello
$ touch ~/testfile
$ sudo tar cf ~/testfile /etc/shadow # ~/testfile is still user-owned
tar: Removing leading `/' from member names
$ tar tf ~/testfile # elevated tar to user-owned file in ~ succeeds
etc/shadow

Now, the relevant documentation in chmod(1) refers specifically to removing or renaming a file, which doesn't apply here. And AFAICT, there is no mention there regarding writes to an existing file with a different owner, root or otherwise.

It seems reasonable enough that elevated privileges SHOULD enable ANY process to write to ANY file. Yet, as demonstrated in the first example given just above, root cannot write to a user-owned file in /tmp!

The last 2 examples above (in ~) demonstrate that it MUST have something to do with the sticky bit.

And unless I'm overlooking it, I'm seeing no indication of this behavior in neither the tar(1) nor bsdtar(1) manpage.

Tangentially (but worth noting), FreeBSD doesn't exhibit this behavior:

$ stat -f %p /tmp # 1=sticky
41777
$ (
t=$(mktemp)
trap "{ rm -f $t; }" EXIT
sudo tar cf $t /etc/master.passwd # bsdtar
tar tf $t
)
tar: Removing leading '/' from member names
etc/master.passwd
$ (
t=$(mktemp)
trap "{ rm -f $t; }" EXIT
sudo gtar cf $t /etc/master.passwd # GNU tar
tar tf $t
)
gtar: Removing leading '/' from member names
etc/master.passwd

Last edited by hexadecagram (2023-01-26 08:16:10)

Offline

#5 2023-01-26 09:25:00

hexadecagram
Member
Registered: 2011-05-20
Posts: 61

Re: Permissions issue involving zsh, mktemp, and tar

Oops, I overlooked the fact that mktemp creates temporary files with 600 perms, so examining the contents of root-owned tar archives should be done in an elevated context:

$ (
  t=$(mktemp)
  trap "{ sudo rm -f $t; }" EXIT
  touch $t
  sudo chown root:root $t
  sudo bsdtar cf $t /etc/shadow
  sudo bsdtar tf $t
)
bsdtar: Removing leading '/' from member names
etc/shadow

When doing so, it becomes obvious that bsdtar behaves the same as GNU tar, putting that mystery to rest.

Anyway, before investigating any further, let me try to summarize. Note that "any program" really just means GNU tar, bsdtar, and tee, because those are all I've tested, but it does seem safe to say that any program would behave the same.

1. Elevating any program to overwrite an existing user-owned file in /tmp fails.
2. Elevating any program to overwrite an existing root-owned file in /tmp succeeds.
3. Elevating any program to overwrite an existing file in ~ succeeds, no matter if user- or root-owned.

seth, you seem to infer that the first thing I describe in the above list fails due to an (AFAICT) undocumented feature in GNU tar (and as I've demonstrated, bsdtar as well) which would prevent restricted files to be stored in unrestricted archives, but if I try to do the same thing in ~, both GNU tar and bsdtar succeed:

$ touch ~/tmpfile
$ sudo tar cf ~/tmpfile /etc/shadow
tar: Removing leading `/' from member names
$ tar tf ~/tmpfile
etc/shadow
$ rm ~/tmpfile
$ touch ~/tmpfile
$ sudo bsdtar cf ~/tmpfile /etc/shadow
bsdtar: Removing leading '/' from member names
$ bsdtar tf ~/tmpfile
etc/shadow

Evidence just seems to keep piling up that the actual reason that elevated programs cannot write to user-owned files in /tmp is because of the sticky bit on /tmp. And thinking about the documentation, "... it prevents unprivileged users from removing ... a file in the directory ...", it would almost fit, but only if the file were unlink(2)'ed before it were open(2)'ed for writing, which may be the case. And if it indeed were, then obviously the effect of the sticky bit applies not just to unprivileged users, but to root as well!

Last edited by hexadecagram (2023-01-26 09:32:45)

Offline

#6 2023-01-26 09:43:45

seth
Member
Registered: 2012-09-03
Posts: 35,274

Re: Permissions issue involving zsh, mktemp, and tar

seth, you seem to infer that the first thing I describe in the above list fails due to an (AFAICT) undocumented feature in GNU tar

Yup, figured as much sad

However the sticky bit restrictions on even the root user are even documented in the wiki:
https://wiki.archlinux.org/title/tmpfs# … root_fails

The chmod documentation seems to be a bit dates itr.
This also seems slightly inconsistent as UID0 can still read and delete foreign files in /tmp and therefore effectively do to them whatever desired.

One remaining aspect w/ this behavior though is that even a root process can not write into a file that's currently opened or esp. mmap'd by another users process.
It can replace it, but the original filehandle stays intact as long as the other process keeps it opened.

Edit: this is btw. not down to some tmpfs detail, setting the sticky bit anywhere causes the same behavior.

Last edited by seth (2023-01-26 09:51:40)

Offline

#7 2023-01-26 21:10:29

hexadecagram
Member
Registered: 2011-05-20
Posts: 61

Re: Permissions issue involving zsh, mktemp, and tar

Interesting.

$ echo 'Hello, world!' > /tmp/tempfile # user-owned file
$ sudo cat /tmp/testfile
Hello, world!
$ ln -s /tmp/testfile /tmp/testfile2 # user-owned symlink
$ sudo cat /tmp/testfile2
cat: /tmp/testfile2: Permission denied
$ rm /tmp/testfile2
$ sudo mv /tmp/tempfile /tmp/tmpfile3 # No output; succeeds (an unprivileged user that did not own it would fail)
$ sudo rm -f /tmp/tempfile3 # No output; succeeds (an unprivileged user that did not own it would fail)

So much for my hypothesis that clobbering might involve a call to unlink(2) before open(2), which, to be fair, seems like it would have to be performed at the syscall level to have the same effect I've witnessed (rather than per application), so it didn't make much sense anyway.

It's not surprising at all that these restrictions on symlinks (which even has a sysctl) and mmap(2) are done with security in mind. It's a bit of a mind-bender that it's being done for root, but not the first time I've seen that sort of thing. I'd just like to know what exactly is standing in the way of open(2) when root calls it for writing in directories with +t. My guess is it's the same thing affecting mmap(2).

Last edited by hexadecagram (2023-01-27 21:22:33)

Offline

Board footer

Powered by FluxBB