Where to report: root fails to edit other users file in sticky bit directory

2020-12-04 Thread MichaIng

Hi Debian team,

I'm sorry to contact you here, but I ran into an IMO extremely important 
bug where I don't know which package is actually responsible.


Even the root user is not permitted to write to an existing file that is 
owned by another user within a sticky bit directory:

---
2020-12-04 14:16:58 root@micha:/tmp# whoami
root
2020-12-04 14:17:07 root@micha:/tmp# ls -dl
drwxrwxrwt 5 root root 100 Dec  4 14:17 .
2020-12-04 14:17:10 root@micha:/tmp# > testfile
2020-12-04 14:17:13 root@micha:/tmp# chown nobody testfile
2020-12-04 14:17:17 root@micha:/tmp# chmod 0777 testfile
2020-12-04 14:17:21 root@micha:/tmp# ls -l testfile
-rwxrwxrwx 1 nobody root 0 Dec  4 14:17 testfile
2020-12-04 14:17:23 root@micha:/tmp# > testfile
bash: testfile: Permission denied
2020-12-04 14:17:26 root@micha:/tmp# rm -v testfile
removed 'testfile'
2020-12-04 14:17:31 root@micha:/tmp# ls -l testfile
ls: cannot access 'testfile': No such file or directory
---
- The sticky bid should only prevent removal of a file by other users, 
not writing to it. root of course should always have permission to do both.
- This issue happens only on Debian Bullseye, independent from Linux 
version and architecture (tested on x86_64 Debian with Linux 5.8 as well 
as Raspberry Pi OS with Linux 5.4).
- It happens as well on at least tmpfs and ext4 file systems, so I 
assume all file systems.
- Not only shell redirects are affected, but all ways to write the file. 
I first observed it during a Python pip install as root user.
- It does not depend on either the shell or the way root was invoked. 
bash, dash, sudo, direct root login all behave the same.


Please advice me who to forward this to or which package is 
responsible/involved.


Best regards,

Micha



Re: Where to report: root fails to edit other users file in sticky bit directory

2020-12-08 Thread MichaIng
Sorry for the late reply guys, I was not subscribed to the list, just 
got the address from the bug report instructions in case the related 
package could not be identified, and thought I get an answer directly to 
my mailbox xD: https://www.debian.org/Bugs/Reporting.en.html


Back to topic.

I totally forgot to make clear that it is an issue on Debian Bullseye 
only. On Buster this would have been recognised much earlier ;).


@Tomas:
---
root@VM-Bullseye:/tmp# id
uid=0(root) gid=0(root) groups=0(root)
root@VM-Bullseye:/tmp# >> testfile
-bash: testfile: Permission denied
root@VM-Bullseye:/tmp# dash -c '>> testfile'
dash: 1: cannot create testfile: Permission denied

---

As said, the issue was first recognised during a Python module install, 
so in a totally different environment. My shell is bash as well, but I 
can reproduce the issue with any shell or any other language to write to 
a file in sticky bit directories.


@Greg
---
root@VM-Bullseye:/tmp# id
uid=0(root) gid=0(root) groups=0(root)
root@VM-Bullseye:~# cd /tmp
root@VM-Bullseye:/tmp# df -T
Filesystem Type 1K-blocks   Used Available Use% Mounted on
udev   devtmpfs   1016164  0   1016164   0% /dev
/dev/sda1  ext4   8189368 584548   7169108   8% /
tmpfs  tmpfs  1018568  0   1018568   0% /dev/shm
tmpfs  tmpfs   407428   5504401924   2% /run
tmpfs  tmpfs 5120  0  5120   0% /run/lock
tmpfs  tmpfs 4096  0  4096   0% /sys/fs/cgroup
tmpfs  tmpfs  1018880  37432981448   4% /tmp
tmpfs  tmpfs51200  8 51192   1% /var/log
root@VM-Bullseye:/tmp# cd /root
root@VM-Bullseye:~# mkdir testdir
root@VM-Bullseye:~# chmod 1777 testdir
root@VM-Bullseye:~# > testdir/testfile
root@VM-Bullseye:~# chown www-data testdir/testfile
root@VM-Bullseye:~# > testdir/testfile
-bash: testdir/testfile: Permission denied
---
The issue is not related to the file system and not related to the 
kernel version. As said I tested in on RPi with their current stable 
Linux 5.4 (now with a second recent update) and on Bullseye with now as 
well two kernel versions. But to be sure, I'll downgrade the kernel to a 
previous major version, probably from Buster backports, just to be sure.


This is a bug clearly, I'm just not sure, if kernel and file system and 
shell/environment does not play a role, which part of the OS does, i.e. 
is sitting between userland programs and kernel/fs driver to verify UNIX 
permissions.


Best regards,

Micha



Re: Where to report: root fails to edit other users file in sticky bit directory

2020-12-08 Thread MichaIng

Am 08.12.2020 um 16:15 schrieb Greg Wooledge:

It *has* to be related to the kernel.  Where else would the permissions
(capabilities) be applied?


That is exactly what I am wondering about. Those are pretty minimal 
Debian install, no SELinux and no AppArmor actively installed, only what 
is pulled in by core system requirements:

---
root@VM-Bullseye:~# echo $(apt-mark showmanual)
apt bash-completion bzip2 ca-certificates cron curl dropbear gnupg 
grub-pc haveged htop ifupdown iputils-ping kmod 
linux-image-4.19.0-13-amd64 nano p7zip parted procps psmisc sudo 
systemd-sysv systemd-timesyncd tiny-initramfs tzdata udev unzip vmtouch 
wget whiptail

---

But there during boot, AppArmor is sort of loaded:
---
[1.051669] AppArmor: AppArmor initialized
[1.328558] AppArmor: AppArmor Filesystem Enabled
[1.782311] AppArmor: AppArmor sha1 policy hashing enabled
[2.753821] systemd[1]: systemd 247.1-3 running in system mode. (+PAM 
+AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP 
+GCRYPT +GNUTLS +ACL +XZ +LZ4 +ZSTD +SECCOMP +BLKID +ELFUTILS +KMOD 
+IDN2 -IDN +PCRE2 default-hierarchy=hybrid)

---
libapparmor1 is pulled in by systemd. There was an update today from +b1 
to +b2 version, but that did not make a difference.



But you didn't try it with buster's kernel yet?


I tried now the current Bullseye kernel, current Buster backports kernel 
and current Buster kernel, it is definitely not kernel-related.



For that matter, how did you run this shell process?  I see "VM" in
your shell prompt, so I'm guessing it's something far more complex
than "I booted my bullseye system, and logged in on the console as root".


It is exactly that simple and can be replicated on all sort of machines 
(Raspberry Pi, VirtualBox VM, VMware and x86_64 notebook). The VM is 
just most simple to test with.



Is there any possibility that the way you invoked your shell process
is messing with the capabilities(7) in such a way that you lost (or
never got) CAP_FOWNER?


---
root@VM-Bullseye:~# capsh --print
Current: =ep
Bounding set 
=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read

Ambient set =
Current IAB:
Securebits: 00/0x0/1'b0
 secure-noroot: no (unlocked)
 secure-no-suid-fixup: no (unlocked)
 secure-keep-caps: no (unlocked)
 secure-no-ambient-raise: no (unlocked)
uid=0(root) euid=0(root)
gid=0(root)
groups=0(root)
Guessed mode: UNCERTAIN (0)
---
cap_fowner is listed.


If it's not that, then someone's going to have to try to reproduce your
results, which would mean running a post-stable kernel, which means
"not me".


Jep, based on the way the list mail address was shown on the Debian bug 
report page, I was actually hoping to reach official maintainers, but 
this seems to be more an end-user support list?



(Also... "their current stable Linux 5.4" --   Is this even DEBIAN?!
If this is a Raspbian or something, you're posting on the wrong mailing
list.)


Raspberry Pi is an ARM SoC, and as such, best featured by the official 
kernel provided by the manufacturer: https://github.com/raspberrypi/linux
I'm running official Debian userland packages but with this 
kernel/bootloader/firmware provided by their repository: 
http://archive.raspberrypi.org/debian/pool/main/r/raspberrypi-firmware/


But it is irrelevant in this regards but only shows clearer the the 
Linux version, hardware and CPU architecture doesn't play a role. I'm 
guessing actually that it is something with systemd and/or AppArmor. 
I'll try to switch to SysV init and purge the AppArmor library completely.


Best regards,

Micha



Re: Where to report: root fails to edit other users file in sticky bit directory

2020-12-08 Thread MichaIng

Am 08.12.2020 um 16:55 schrieb to...@tuxteam.de:

@Tomas:
---
root@VM-Bullseye:/tmp# id
uid=0(root) gid=0(root) groups=0(root)
root@VM-Bullseye:/tmp# >> testfile
-bash: testfile: Permission denied
root@VM-Bullseye:/tmp# dash -c '>> testfile'
dash: 1: cannot create testfile: Permission denied


Oh, I see. Strange error message though -- I'd expect dash to
try to open the file in append mode, not to `create' it.

Thanks for reporting back, cheers
  - t


I was also wondering about that, but dash prints this message regardless 
if the file exists already or not, if permissions are not there. Note 
that creating a new file works fine, removing a file as well, only 
writing to an existing file fails, regardless of shell or originating 
program.


I now also tested to switch from systemd to SysV init, which allowed to 
remove libapparmor1. I even purged udev (which breaks network) to get 
rid of any systemd package, but the issue remains. Strangely the three 
AppArmor init messages remain:

--
[1.051669] AppArmor: AppArmor initialized
[1.328558] AppArmor: AppArmor Filesystem Enabled
[1.782311] AppArmor: AppArmor sha1 policy hashing enabled
--
I think this is fixed part of grub or the kernel then. However, on RPi, 
with different kernel and different bootloader, those messages are not 
present, but the issue is.


So I'm still completely out of ideas.

Btw, if someone knows an "official" Debian mailing list with 
maintainers/developers, where this can be reported, that might be 
helpful. If it is clearly related to a certain package, things are easy 
to address correctly, but in this case I have no clue.


I think best to debug is if someone with deeper insights is replicating 
this on an own system. But of course I'll go on trying/testing ideas, 
that come to my mind of thrown in here.


Best regards,

Micha



Re: Where to report: root fails to edit other users file in sticky bit directory

2020-12-08 Thread MichaIng
Good idea, although it would have been recognised much earlier during 
nearly every normal system operation:

---
root@micha:/tmp# set -o | grep noclobber
noclobber   off
---

strace is a fantastic idea, but it seems to fail on the lowest level 
"EACCES (Permission denied)":

---
root@VM-Bullseye:~# strace touch testdir/testfile
execve("/usr/bin/touch", ["touch", "testdir/testfile"], 0x7ffc117f64c8 
/* 15 vars */) = 0

brk(NULL)   = 0x562ade0be000
access("/etc/ld.so.preload", R_OK)  = -1 ENOENT (No such file or 
directory)

openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=10074, ...}) = 0
mmap(NULL, 10074, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fd0797bd000
close(3)= 0
openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, 
"\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0@n\2\0\0\0\0\0"..., 832) 
= 832

fstat(3, {st_mode=S_IFREG|0755, st_size=1839792, ...}) = 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) 
= 0x7fd0797bb000
mmap(NULL, 1852680, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 
0x7fd0795f6000

mprotect(0x7fd07961b000, 1662976, PROT_NONE) = 0
mmap(0x7fd07961b000, 1355776, PROT_READ|PROT_EXEC, 
MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x25000) = 0x7fd07961b000
mmap(0x7fd079766000, 303104, PROT_READ, 
MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17) = 0x7fd079766000
mmap(0x7fd0797b1000, 24576, PROT_READ|PROT_WRITE, 
MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1ba000) = 0x7fd0797b1000
mmap(0x7fd0797b7000, 13576, PROT_READ|PROT_WRITE, 
MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fd0797b7000

close(3)= 0
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) 
= 0x7fd0795f4000

arch_prctl(ARCH_SET_FS, 0x7fd0797bc5c0) = 0
mprotect(0x7fd0797b1000, 12288, PROT_READ) = 0
mprotect(0x562adcd52000, 4096, PROT_READ) = 0
mprotect(0x7fd0797ea000, 4096, PROT_READ) = 0
munmap(0x7fd0797bd000, 10074)   = 0
brk(NULL)   = 0x562ade0be000
brk(0x562ade0df000) = 0x562ade0df000
openat(AT_FDCWD, "/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=1827600, ...}) = 0
mmap(NULL, 1827600, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fd079435000
close(3)= 0
openat(AT_FDCWD, "testdir/testfile", 
O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 EACCES (Permission denied)

utimensat(AT_FDCWD, "testdir/testfile", NULL, 0) = 0
close(1)= 0
close(2)= 0
exit_group(0)   = ?
+++ exited with 0 +++
---

I disabled file system caching by remounting rootfs with "sync" option, 
but that didn't help either. Other file systems with UNIX permissions 
are outstanding: F2FS, Btrfs, XFS, NTFS with 3g driver, will try that as 
well.


I btw reported the issue to the testing list now, which seems to be the 
better place to report unspecific issues with Bullseye. Although the 
list is not very active :\. Let's see, my mail did not appear yet: 
https://lists.debian.org/debian-testing/2020/12/threads.html




Re: Where to report: root fails to edit other users file in sticky bit directory

2020-12-08 Thread MichaIng
I think the topic with the modes just applies when the file is actually 
created, hence not existing yet.


However, aiming for a method to edit a file without O_CREAT, and voila:
---
root@VM-Bullseye:~# cat testdir/testfile
143
root@VM-Bullseye:~# sed -i 's/1/5/' testdir/testfile
root@VM-Bullseye:~# cat testdir/testfile
543
root@VM-Bullseye:~# > testdir/testfile
-bash: testdir/testfile: Permission denied
---

You nailed it! Now checking the kernel patch:
---
root@VM-Bullseye:~# sysctl fs.protected_regular
fs.protected_regular = 2
root@VM-Bullseye:~# sysctl fs.protected_regular=0
fs.protected_regular = 0
root@VM-Bullseye:~# > testdir/testfile
root@VM-Bullseye:~# cat testdir/testfile
root@VM-Bullseye:~#
---

Bingo!

Okay, so this is a security feature with the aim to prevent accidental 
writes to a file owned by a potential attacker. I.e. since the directory 
is world-writeable, an attacker can place a file that is knows is 
written to by another user/victim. The victim actually aims to create a 
new file (or write to it's own existing one), but now writes to the 
prepared attackers file, which can then do whatever (s)he wants to do 
with it as of ownership, to break the victims process or place different 
information inside (then originally stored), like poisoning a cache and 
such.


Yeah, somehow a thinkable scenario, although at least with systemd there 
is PrivateTmp=true for this, and critical/sensitive information should 
simply otherwise not be stored into /tmp root, a restricted sub 
directory or /run or something like that. But the biggest problem is 
that, while this effectively breaks sharing files (writeable) between 
multiple users/processes, as many methods include O_CREAT, it is not 
documented anywhere related to /tmp mount and sticky bit, so it is 
mostly unexpected, isn't it? The results are errors which are hard to 
debug, in my case it took me a full day to get to the essence of the 
issue, while first I reviewed and re-tested and changed back and forth a 
Python script (of some software I use, not my own).


And, root should IMO still be allowed to do it, as practically it can 
anyway via chown. root can as well remove any file, regardless of sticky 
bit, so this would be consistent.


Relevant package is then: procps

Ah, btw on Buster, by default it's disabled:
---
2020-12-08 21:39:47 root@VM-Buster:~# sysctl fs.protected_regular
fs.protected_regular = 0
---

Many thanks for looking deeper at O_CREAT guys, I likely wouldn't have 
searched into this direction :)!


Best regards and stay healthy,

Micha



Re: Where to report: root fails to edit other users file in sticky bit directory

2020-12-08 Thread MichaIng

Am 08.12.2020 um 22:03 schrieb Greg Wooledge:

Unexpected clobberin' by root is the actual *worst* case that this
security feature is trying to protect against.  Imagine this hypothetical
scenario:

1) Process A running as regular user alice creates a temp file in /tmp,
owned by alice.

2) Dumb process B running as root decides to use the exact same temp file
name that A is using.  It opens the file naively, and writes some
stuff to it, intending to read it back later.

3) Process A rewinds the file and writes new stuff to it.

4) Process B reads process A's data from the file, thinking it was going
to read its own data.

5) Process B calculates the wrong thing, and turns off the life support
system.

I don't know how realistic this is, or how closely it mirrors the thought
processes of the people who came up with the modification.  But if you're
going to make this modification at all, it needs to affect root, or else
it's pointless.


Such a (custom) process should simply not run as root, should create an 
own temporary sub directory with limited permissions and write it's own 
files there. If really something is written to the world-writeable /tmp 
directory root, it must be expected that it can be read and written to 
or created by other users. Btw. the way the security feature is 
implemented, explicitly allows anyone writing to the file (as long as 
UNIX permissions are given), so it does not totally rule out your 
scenario, but only when process B uses a O_CREAT access method. But it 
could instead check if the file exists first, and otherwise write to it 
without O_CREAT.


But I got the point, as especially root processes are likely more 
sensitive and create larger damage when manipulated (accidentally or 
intentionally) such a way.



Your unique situation, where user A is putting a file in /tmp for some
reason, and then user R is supposed to edit it in place, is really weird.
I don't know why you're putting this important shared file in /tmp, but
you might want to move it to a more appropriate place.


There is no reason to use the /tmp root (without sub directory) aside of 
expecting that the file is potentially shared, IMO. If it must only be 
accessed by the same process/user, it should be placed elsewhere, at 
least into a sub directory or a private /tmp.


Sharing files through /tmp is probably rare, but /tmp it is for 
temporary files, it's by default a tmpfs (relevant when one wants to 
minimize file system writes, e.g. drive spin up or SD cards with short 
life cycle, or runs a R/O system), and it's the only FHS directory that 
is world-writeable by default. So I cannot imagine any better place to 
share temporary information through files cross-process/user then /tmp :D.


So yeah, basically the feature prevents users, who do not know what they 
are doing, from rare but possible errors and attacks, but it limits 
users, who know that they are doing, from rarely relevant possibilities 
xD. I think it is all fine as long as it's well documented, i.e. part of 
docs and man pages that deal with the sticky bit, like man chmod(1).


Best regards,

Micha



Re: Where to report: root fails to edit other users file in sticky bit directory

2020-12-09 Thread MichaIng
Please note that it by default appears on Bullseye only. See that last 
mails regarding this issue, the related changed sysfs setting has 
identified already do:

---
sysctl fs.protected_regular=2
---
and retry the steps, which will then fail.
---
sysctl fs.protected_regular=0
---
to revert to default until up to Buster. From Bullseye on that defaults 
to "2" which prevents any user from write + "O_CREAT" to a file within a 
world-writeable + sticky bit directory (1777) that is owned by another user.


Best regards,

Micha



Re: Where to report: root fails to edit other users file in sticky bit directory

2020-12-09 Thread MichaIng
Your right /tmp is not a tmpfs by default on Debian. I though it was, 
maybe being too much used to it as this is configured by default on our 
images. /dev/shm or /run would work better then, although /run IMO is 
more aimed for non-temporary files, relevant through the whole runtime 
of the related process or system, while /tmp is more aimed for 
short-term temporary files. However it was/is not my choice to use /tmp 
in the particular case and out of my control.


Background, if interested:
---
In my particular case where I ran into the issue, it is a 3rd party 
software that chooses to store information to /tmp/ via sub 
process which is then read by originating process. Indeed the 
circumstance is a bid special, the solution is even commented as an 
"ugly" one within the code, but no better method had been found until 
now. The software collects information about the Python environment by 
doing a dummy module install (that is aimed to fail). The dummy modules 
installer collects info about where it was installed to 
(venv/user-level/system-level, ...) and writes that to /tmp/ 
to be read by the originating Python script. It has an internal updater 
which invokes pip the "correct" way based on the /tmp/ 
content (e.g. --user flag or not).


I want the software to run as system service with an own limited user, 
but aim to have it installed as global/system Python module to 
/usr/local/lib|bin instead of in --user mode into its own UNIX user home 
directory, or as vnev, to prevent doubled Python module installs (target 
is small embedded systems with potentially limited disk space), easier 
access/maintenance for the real (login) user and clear separation 
between data/config and the Python modules. To retain the functionality 
of the internal updater, it requires specifically limited "sudo pip 
install " permissions to self-upgrade and do it's Python 
environment collection dummy install that is out of my control. The 
problem is now that it pre-creates /tmp/ as its limited 
service user but since pip is called via sudo, the dummy installer then 
tries and fails to write to that file as root user.

---

I am actually sort of Linux distributor, more precisely developing 
Debian-based images mostly for ARM SBCs together with a tool set to 
easily install and configure system a bunch of software titles. See the 
domain of my mail address. If I was a system administrator only, of 
course, why should I feel forced to follow any standard, but as a 
software developer I clearly disagree with you! The FHS is exactly what 
software developers should then be able to count on and respect 
themselves (to allow others count on it), which directories are present 
and used in the same (at least similar) way by the distributions own 
software packages as well as most 3rd party software installers. Without 
FHS one would quickly have all sorts of files messed across a bunch of 
different directory structures and sub structures, making it impossible 
for admins to follow any logic to find certain types of files, like 
software and system configuration files, variable data, temporary files 
etc, also to know where files are expected to survive a reboot and where 
not (potentially tmpfs) etc. Without FHS (or any other standard across 
Linux/UNIX systems) we had a mess, so FHS is no "crap" but very valuable 
and important, IMO.


But that is a discussion that has nothing to do with the originating 
issue, which has been identified thanks to your help! :)
It's now a bid others and whether the default has actually been changed 
intentionally, and if so more like "why not" or if there have been 
actual concerns, serious enough to change a default, which implies 
different and probably unexpected behaviour. And if so, if there is a 
plan to have this documented a bid wider.


Best regards and stay healthy,

Micha