Pretending to be root inside PRoot
While working on PRoot to improve the extension that fake the root user, I (re)discovered an old article that I never published before. So let's focus on the fake_id0 feature and on how it allows to use package manager directly inside the root file systems.
Some root causes
In a previous article, I described a way to jump into a root file system in order to compile and tests softwares in this new environment. We used PRoot to jump in this new root file system and to bind some needed resources, like
/sys, in this file system.
Inside, this fresh root file system, the first and obvious step is to use your favorite package manager to install some tools like git. For instance on a Debian file system:
#!/bin/bash ivoire@machine: /tmp% proot -b /dev -b /proc -b /sys -b $HOME -b /tmp -b /var/run -0 debian-i386-sid root@machine: /tmp% apt-get install git Reading package lists... Done Building dependency tree Reading state information... Done The following NEW packages will be installed: git git-man libbsd0 libedit2 liberror-perl openssh-blacklist openssh-blacklist-extra openssh-client rsync xauth 0 upgraded, 10 newly installed, 0 to remove and 0 not upgraded. Need to get 0 B/12.9 MB of archives. After this operation, 26.4 MB of additional disk space will be used. Do you want to continue [Y/n]? [...] Unpacking git (from .../git_1%3a184.108.40.206-2_i386.deb) ... dpkg: error processing /var/cache/apt/archives/git_1%3a220.127.116.11-2_i386.deb (--unpack): unable to open '/usr/share/perl5/Git/SVN/Memoize/YAML.pm.dpkg-new': Permission denied Errors were encountered while processing: /var/cache/apt/archives/git_1%3a18.104.22.168-2_i386.deb E: Sub-process /usr/bin/dpkg returned an error code (1)
A strange error appears:
unable to open '/usr/share/perl5/Git/SVN/Memoize/YAML.pm.dpkg-new': Permission denied
The error is a "Permission denied", which seems impossible because:
- Every files in this root file system, belongs to the current user
- PRoot is launched with the
-0switch that hooks some syscall and avoid permissions issues
For these two reasons, we should not have any permission denied!
In fact, the bug is tricker:
apt-get is relying on the fact that
root can browse and create files in a directory where it does not have any rights. For instance the following:
#!/bin/bash ~ mkdir /tmp/test ~ chmod 000 /tmp/test ~ ls -ld /tmp/test d--------- 2 root root 4.0K /tmp/test/ ~ touch /tmp/test/one_file ~ ls -l /tmp/test/one_file -rw-r--r-- 1 root root 0 /tmp/test/one_file
This script will obviously fail for every users, except for
Just-in-Time permission changes
This behavior has to be taken into account by the
-0 switch if we want it to behave like root.
We introduced an new mechanism in PRoot, only activated by
-0, that change the permission when entering a syscall and restoring them when leaving the syscall. The following graph explains the patching mechanism:
For every path segment, the PRoot extension looks for the permissions and patch them if needed. When leaving the syscall, every changes are restored. This way, accessing to directories is possible even without the right permissions.
The algorithm is quite simple:
- Entering the syscall
- Patching the premissions
- Running the syscall
- Unpatching the permissions
- Leaving the syscall
With this feature, it's now possible to use
yum under PRoot to manage the packages in a file system.
If you haven't try it, I advice you to try to jump into a file system using PRoot to compile and test some of your projects. This may find some tricky bugs that only appears in some distributions that you don't run on your development machine.