2020-05-13 15:03:27

by Patrick Donnelly

[permalink] [raw]
Subject: file system permissions regression affecting root

In newer kernels (at least 5.6), it appears root is not able to write
to files owned by other users in a sticky directory:

$ uname -r
5.6.11-arch1-1
$ stat -f /tmp
File: "/tmp"
ID: 0 Namelen: 255 Type: tmpfs
Block size: 4096 Fundamental block size: 4096
Blocks: Total: 2005160 Free: 2005092 Available: 2005092
Inodes: Total: 2005160 Free: 2005112
$ stat /tmp
File: /tmp
Size: 440 Blocks: 0 IO Block: 4096 directory
Device: 2fh/47d Inode: 21533 Links: 20
Access: (1777/drwxrwxrwt) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2020-05-11 11:50:52.780667565 -0700
Modify: 2020-05-13 07:40:19.617941285 -0700
Change: 2020-05-13 07:40:19.617941285 -0700
Birth: -
$ touch /tmp/foo
$ stat /tmp/foo
File: /tmp/foo
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: 2fh/47d Inode: 3441684 Links: 1
Access: (0640/-rw-r-----) Uid: ( 1000/pdonnell) Gid: ( 985/ users)
Access: 2020-05-13 07:40:29.218026785 -0700
Modify: 2020-05-13 07:40:29.218026785 -0700
Change: 2020-05-13 07:40:29.218026785 -0700
Birth: -
$ sudo /bin/sh -c 'echo 1 > /tmp/foo'
/bin/sh: /tmp/foo: Permission denied
$ sudo strace -f -- /bin/sh -c 'echo 1 > /tmp/foo' |& grep foo
execve("/bin/sh", ["/bin/sh", "-c", "echo 1 > /tmp/foo"],
0x7fff92dec300 /* 15 vars */) = 0
openat(AT_FDCWD, "/tmp/foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = -1
EACCES (Permission denied)
write(2, "/bin/sh: /tmp/foo: Permission de"..., 37/bin/sh: /tmp/foo:
Permission denied


Compare to Linux 4.18:

$ uname -r
4.18.0-147.3.1.el8_1.x86_64
$ stat /dev/shm
File: /dev/shm
Size: 100 Blocks: 0 IO Block: 4096 directory
Device: 16h/22d Inode: 15466 Links: 2
Access: (1777/drwxrwxrwt) Uid: ( 0/ root) Gid: ( 0/ root)
Context: system_u:object_r:tmpfs_t:s0
Access: 2020-05-12 17:37:07.029131257 +0000
Modify: 2020-05-13 14:35:44.161036943 +0000
Change: 2020-05-13 14:35:44.161036943 +0000
Birth: -
$ stat -f /dev/shm
File: "/dev/shm"
ID: 0 Namelen: 255 Type: tmpfs
Block size: 4096 Fundamental block size: 4096
Blocks: Total: 9243647 Free: 9243604 Available: 9243604
Inodes: Total: 9243647 Free: 9243643
$ touch /dev/shm/foo
$ stat /dev/shm/foo
File: /dev/shm/foo
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: 16h/22d Inode: 5616861 Links: 1
Access: (0640/-rw-r-----) Uid: ( 1156/pdonnell) Gid: ( 1156/pdonnell)
Context: unconfined_u:object_r:user_tmp_t:s0
Access: 2020-05-13 14:44:55.121908033 +0000
Modify: 2020-05-13 14:44:55.121908033 +0000
Change: 2020-05-13 14:44:55.121908033 +0000
Birth: -
$ sudo -- /bin/sh -c 'echo 1 > /dev/shm/foo'
$

This seems to be related to the directory being owned by root; it does
not happen when the directory is owned by the user:

$ uname -r
5.6.11-arch1-1
$ sudo chown pdonnell:users gtmp
$ stat gtmp
File: gtmp
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: fe04h/65028d Inode: 2819062 Links: 2
Access: (1777/drwxrwxrwt) Uid: ( 1000/pdonnell) Gid: ( 985/ users)
Access: 2020-05-13 07:47:06.344892575 -0700
Modify: 2020-05-13 07:50:24.709987998 -0700
Change: 2020-05-13 07:52:52.137963637 -0700
Birth: 2020-05-13 07:34:09.937974845 -0700
$ stat -f gtmp
File: "gtmp"
ID: f24a3528a175df48 Namelen: 255 Type: ext2/ext3
Block size: 4096 Fundamental block size: 4096
Blocks: Total: 36495867 Free: 8991668 Available: 7120360
Inodes: Total: 9338880 Free: 8147228
$ touch gtmp/foo
$ stat gtmp/foo
File: gtmp/foo
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fe04h/65028d Inode: 2754033 Links: 1
Access: (0640/-rw-r-----) Uid: ( 1000/pdonnell) Gid: ( 985/ users)
Access: 2020-05-13 07:53:10.218124141 -0700
Modify: 2020-05-13 07:53:10.218124141 -0700
Change: 2020-05-13 07:53:10.218124141 -0700
Birth: 2020-05-13 07:53:10.218124141 -0700
$ sudo strace -f -- /bin/sh -c 'echo 1 > gtmp/foo' |& grep foo
execve("/bin/sh", ["/bin/sh", "-c", "echo 1 > gtmp/foo"],
0x7ffe03362430 /* 15 vars */) = 0
openat(AT_FDCWD, "gtmp/foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
$ rm gtmp/foo
$ sudo chown root:root gtmp
$ touch gtmp/foo
# stat gtmp/foo
File: gtmp/foo
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: fe04h/65028d Inode: 2754033 Links: 1
Access: (0640/-rw-r-----) Uid: ( 1000/pdonnell) Gid: ( 985/ users)
Access: 2020-05-13 07:55:18.892599600 -0700
Modify: 2020-05-13 07:55:18.892599600 -0700
Change: 2020-05-13 07:55:18.892599600 -0700
Birth: 2020-05-13 07:55:18.892599600 -0700
$ sudo strace -f -- /bin/sh -c 'echo 1 > gtmp/foo' |& grep foo
execve("/bin/sh", ["/bin/sh", "-c", "echo 1 > gtmp/foo"],
0x7fff588732f0 /* 15 vars */) = 0
openat(AT_FDCWD, "gtmp/foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = -1
EACCES (Permission denied)
write(2, "/bin/sh: gtmp/foo: Permission de"..., 37/bin/sh: gtmp/foo:
Permission denied


--
Patrick Donnelly


2020-05-13 16:13:53

by Al Viro

[permalink] [raw]
Subject: Re: file system permissions regression affecting root

On Wed, May 13, 2020 at 08:00:28AM -0700, Patrick Donnelly wrote:
> In newer kernels (at least 5.6), it appears root is not able to write
> to files owned by other users in a sticky directory:

Yes. Controlled by /proc/sys/fs/protected_regular, which systemd crowd
has decided to enable in commit 2732587540035227fe59e4b64b60127352611b35
Author: Lucas Werkmeister <[email protected]>
Date: Wed Jan 16 00:16:10 2019 +0100

Enable regular file and FIFO protection

These sysctls were added in Linux 4.19 (torvalds/linux@30aba6656f), and
we should enable them just like we enable the older hardlink/symlink
protection since v199. Implements #11414.

in their tree. The relevant part is this:
diff --git a/sysctl.d/50-default.conf b/sysctl.d/50-default.conf
index b0645f33e7..27084f6242 100644
--- a/sysctl.d/50-default.conf
+++ b/sysctl.d/50-default.conf
@@ -36,3 +36,7 @@ net.core.default_qdisc = fq_codel
# Enable hard and soft link protection
fs.protected_hardlinks = 1
fs.protected_symlinks = 1
+
+# Enable regular file and FIFO protection
+fs.protected_regular = 1
+fs.protected_fifos = 1

so if you want the normal behaviour (and I certainly agree that the value
of that "protection" is not terribly high - I don't enable it on any of
my boxen and I don't use systemd, so they can't make those decisions for
me), I would suggest going into /etc/sysctl.d/ and telling the damn
thing _not_ to enable that.

From the same commit:
+ * The fs.protected_regular and fs.protected_fifos sysctls, which were
+ added in Linux 4.19 to make some data spoofing attacks harder, are
+ now enabled by default. While this will hopefully improve the
+ security of most installations, it is technically a backwards
+ incompatible change; to disable these sysctls again, place the
+ following lines in /etc/sysctl.d/60-protected.conf or a similar file:
+
+ fs.protected_regular = 0
+ fs.protected_fifos = 0
+
+ Note that the similar hardlink and symlink protection has been
+ enabled since v199, and may be disabled likewise.

2020-05-13 16:54:29

by Patrick Donnelly

[permalink] [raw]
Subject: Re: file system permissions regression affecting root

On Wed, May 13, 2020 at 9:11 AM Al Viro <[email protected]> wrote:
>
> On Wed, May 13, 2020 at 08:00:28AM -0700, Patrick Donnelly wrote:
> > In newer kernels (at least 5.6), it appears root is not able to write
> > to files owned by other users in a sticky directory:
>
> Yes. Controlled by /proc/sys/fs/protected_regular, which systemd crowd
> has decided to enable in commit 2732587540035227fe59e4b64b60127352611b35
> [...]

Thanks for the information Al!

However, it seems odd that this depends on the owner of the directory.
i.e. this protection only seems to be enforced if the sticky directory
is owned by root. That's expected?


--
Patrick Donnelly

2020-05-17 04:52:27

by Christian Kujau

[permalink] [raw]
Subject: Re: file system permissions regression affecting root

On Wed, 13 May 2020, Patrick Donnelly wrote:
> However, it seems odd that this depends on the owner of the directory.
> i.e. this protection only seems to be enforced if the sticky directory
> is owned by root. That's expected?

According to the documentation[0] this appears to be intentional:

protected_regular:
[...]
When set to "1" don't allow O_CREAT open on regular files that we
don't own in world writable sticky directories, unless they are
owned by the owner of the directory.

C.

[0] https://www.kernel.org/doc/Documentation/sysctl/fs.txt
--
BOFH excuse #263:

It's stuck in the Web.