why does mount ignore effective user id - linux

I'm wondering why my version of mount appears to ignore the effective user ID...
I have this C program owned by root with permission u+s:
int main() {
execl("/bin/mount", "/bin/mount", "/mnt/abc", (char *)0);
}
When a regular user runs it, it complains about not being root. I can work around it like this:
int main() {
setuid(0);
execl("/bin/mount", "/bin/mount", "/mnt/abc", (char *)0);
}
I read that bash changes the effective uid to the real uid as a safety feature. (see Calling a script from a setuid root C program - script does not run as root) However, I don't see why mount should do that. Does anyone know?
My mount version is:
mount from util-linux 2.29.2 (libmount 2.29.2: selinux, btrfs, assert, debug)

This happens because mount is designed to run as suid root.
$ ls -l /bin/mount
-rwsr-xr-x 1 root root 44200 Mar 6 13:31 /bin/mount
^
CDs or floppy drives would typically have the user option set in fstab to allow non-root users to access removable media. mount was made SUID root to support this, and it therefore checks the real UID to determine what you're allowed to do.

Related

test -x in Mounted Filesystem

I'm using QEMU to test Raspberry Pi before putting the image onto an SD card. I'm setting up an automated script to put some files onto the Pi, among other things, so that when I put the SD card into the Pi, it is immediately usable. I think I've run into a quirk in how permissions work, but I'm not sure.
When you run test -x, the file is supposed to be executable. Basically, the x bit is supposed to be on for your user. However, this doesn't seem to apply to files inside mounted filesystems.
The host is Ubuntu, and the guest backing image is Raspberry Pi Buster. I created the mountpoint with guestmount, because I was mounting a snapshot, not the original, and this seems to be the only/best way to do that. The basic flow was:
qemu-img convert -Oqcow2 raspberry-pi.img raspberry-pi.qcow
qemu-img create -f qcow2 snapshot.qcow -b raspberry-pi.qcow
sudo guestmount -a 'snapshot.qcow' -i 'mountpoint/'
For example, I have a file outside the repository. The file I'm testing inside the mountpoint was created by root, so I chmoded this file to root for comparison:
$ sudo ls -l --author ~/test/file
-rw-r--r-- 1 root root root 1133 Oct 8 21:43 /home/me/test/file
$ sudo test -x ~/test/file && echo 'exists' || echo 'doesn\'t exist'
doesn't exist
However, for a file inside the mountpoint, with the same permissions, the test is successful:
$ sudo ls -l --author mountpoint/home/pi/test/file
-rw-r--r-- 1 root root root 0 Oct 8 22:41 mountpoint/home/pi/test/file
$ sudo test -x ~/test/file && echo 'exists' || echo 'doesn\'t exist'
exists
Why is the file inside the mountpoint executable, whereas the one outside is not executable? Is this because the mounted filesystem is a different architecture (x86 vs. ARM)? Is it because I'm using guestmount, and the filesystem isn't the real filesysem, but an amalgamation of the snapshot & the original file? Or is this just the way mounting works? Where can I find more resources on this peculiar behavior, like other permission quirks I might encounter?
If you need any more information about the host or guest, please ask.
This is a bug in libguestfs used by guestmount. You can see it here:
/* Root user should be able to access everything, so only bother
* with these fine-grained tests for non-root. (RHBZ#1106548).
*/
if (fuse->uid != 0) {
[...]
if (mask & X_OK)
ok = ok &&
( fuse->uid == statbuf.st_uid ? statbuf.st_mode & S_IXUSR
: fuse->gid == statbuf.st_gid ? statbuf.st_mode & S_IXGRP
: statbuf.st_mode & S_IXOTH);
}
The FS takes a shortcut saying that since you're root you have full access, so there's no point checking the permissions.
As you've demonstrated, this is not true. Root should only have execute permissions for directories, and for files where at least one of the execute bits is set.
I was unable to build the project to submit a patch, but you can file a bug.

Normal user touching a file in /var/run failed

I have a program called HelloWorld belonging to user test
HelloWorld will create a file HelloWorld.pid in /var/run to keep single instance.
I using following command to try to make test can access /var/run
usermod -a -G root test
However, when I run it, falied
could someone help me?
What are the permissions on /var/run? On my system, /var/run is rwxr-xr-x, which means only the user root can write to it. The permissions do not allow write access by members of the root group.
The normal way of handling this is by creating a subdirectory of /var/run that is owned by the user under which you'll be running your service. E.g.,
sudo mkdir /var/run/helloworld
sudo chown myusername /var/run/helloworld
Note that /var/run is often an ephemeral filesystem that disappears when your system reboots. If you would like your target directory to be created automatically when the system boots you can do that using the systemd tmpfiles service.
Some linux systems store per-user runtime files in /var/run/user/UID/.
In this case you can create your pid file in /var/run/user/$(id -u test)/HelloWorld.pid.
Alternatively just use /tmp.
You may want to use the user's name as a prefix to the pid filename to avoid collision with other users, for instance /tmp/test-HelloWorld.pid.

How the privileged commands are controlled?

How the Operating system prevents normal users from executing commands like fdisk and umount eventhough the commands have execute permissions for everyone ?
[root#r7prd1 ~]# ls -la $(which umount)
-rwsr-xr-x. 1 root root 31960 Aug 21 2015 /usr/bin/umount
[root#r7prd1 ~]# ls -la $(which fdisk)
-rwxr-xr-x. 1 root root 182472 Aug 21 2015 /usr/sbin/fdisk
There probably may be some situations when it may be worth to disallow user to execute any binaries (I suppose it may be one of countermeasures against privilege escalation exploits). But in many cases regular users are able to execute their own binaries, so what if user will write and compile fdisk or something similar by himself? Really, you don't want to disallow user to run fdisk. You just want to disallow fdisk or any other program to modify the system state in some way. So regular user really can execute fdisk:
$ fdisk --help
Usage:
fdisk [options] <disk> change partition table
fdisk [options] -l [<disk>] list partition table(s)
...
What regular user actually cannot do is executing restricted operations:
$ fdisk /dev/sda
Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
fdisk: cannot open /dev/sda: Permission denied
So fdisk started successfully, printed some messages. Then it tried to open raw disk device /dev/sda and it was that operation that was really restricted by permissions, so fdisk just complained that it cannot do anything and exited.
There are some cases, though, when you may want to restrict executability of some binaries by some users. When administrator or OS maintainer want regular user to be able to execute some privileged action (such as mounting some partition that this particular user is allowed to by some record in the /etc/fstab), them set up some special hardened binaries such as mount or sudo with set-user-ID permission:
$ ls -l /bin/mount /usr/bin/sudo
-rwsr-xr-x 1 root root 40152 May 27 02:31 /bin/mount
-rwsr-xr-x 1 root root 136808 Aug 17 16:20 /usr/bin/sudo
When such binary is executed, the kernel gives it not the user ID of the calling user, but, in this case, UID 0 (root). Because regular user cannot set binaries up this way (root owner and set-UID bit set), then it may be theoretically worth restricting executability of these binaries to some particular group (but in the above case, they are world-executable and check permissions of calling user by themselves. I don't really know, if executability restrictions of set-UID executables cannot be circumvented in some way and whether such as approach is really widely used by someone).
And one extra note: in case of fdisk on your system, it is installed to /usr/sbin directory that may or may not be in the PATH variable of regular users, so fdisk may or may not be executed by regular user by just typing fdisk at command prompt, but it is not really a restriction (one may simply specify full path to executable on the command line).

Sshfs as regular user through fstab

I'd like to mount a remote directory through sshfs on my Debian machine, say at /work. So I added my user to fuse group and I run:
sshfs user#remote.machine.net:/remote/dir /work
and everything works fine. However it would be very nice to have the directory mounted on boot. So I tried the /etc/fstab entry given below:
sshfs#user#remote.machine.net:/remote/dir /work fuse user,_netdev,reconnect,uid=1000,gid=1000,idmap=user 0 0
sshfs asks for password and mounts almost correctly. Almost because my regular user has no access to the mounted directory and when I run ls -la /, I get:
d????????? ? ? ? ? ? work
How can I get it with right permissions trough fstab?
Using option allow_other in /etc/fstab allows other users than the one doing the actual mounting to access the mounted filesystem. When you booting your system and mounting your sshfs, it's done by user root instead of your regular user. When you add allow_other other users than root can access to mount point. File permissions under the mount point still stay the same as they used to be, so if you have a directory with 0700 mask there, it's not accessible by anyone else but root and the owner.
So, instead of
sshfs#user#remote.machine.net:/remote/dir /work fuse user,_netdev,reconnect,uid=1000,gid=1000,idmap=user 0 0
use
sshfs#user#remote.machine.net:/remote/dir /work fuse user,_netdev,reconnect,uid=1000,gid=1000,idmap=user,allow_other 0 0
This did the trick for me at least. I did not test this by booting the system, but instead just issued the mount command as root, then tried to access the mounted sshfs as a regular user.
Also to complement previous answer:
You should prefer the [user]#[host] syntax over the sshfs#[user]#[host] one.
Make sure you allow non-root users to specify the allow_other mount option in /etc/fuse.conf
Make sure you use each sshfs mount at least once manually while root so the host's signature is added to the .ssh/known_hosts file.
$ sudo sshfs [user]#[host]:[remote_path] [local_path] -o allow_other,IdentityFile=[path_to_id_rsa]
REF: https://wiki.archlinux.org/index.php/SSHFS
Also, complementing the accepted answer: there is a need that the user on the target has a right to shell, on target machine: sudo chsh username -> /bin/bash.
I had a user who had /bin/false, and this caused problems.

How to run a command in a chroot jail not as root and without sudo?

I'm setting up a minimal chroot and want to avoid having sudo or su in it but still run my processes as non-root. This is a bit of a trick as running chroot requiers root. I could write a program that does this that would look something like:
uid = LookupUser(args[username]) // no /etc/passwd in jail
chroot(args[newroot])
cd("/")
setuids(uid)
execve(args[exe:])
Is that my best bet or is there a standard tool that does that for me?
I rolled my own here:
If you invoke chroot from root, the chroot option --userspec=USER:GROUP will run the command under the non-root UID/GID.
By the way, the option '--userspec' is first introduced in coreutils-7.5 according to a git repository git://git.sv.gnu.org/coreutils.
fakechroot, in combination with fakeroot, will allow you to do this. They'll make all programs that are running act as if they're being run in a chroot as root but they'll actually be running as you.
See also fakechroot's man page.
You can make use of linux capabilities to give your binary the ability to call chroot() w/o being root. As an example, you can do this to the chroot binary. As non-root, normally you'd get this:
$ chroot /tmp/
chroot: cannot change root directory to /tmp/: Operation not permitted
But after you run the setcap command:
sudo setcap cap_sys_chroot+ep /usr/sbin/chroot
It will let you do the chroot call.
I don't recommend you do this to the system's chroot, that you instead do it to your own program and call chroot. That way you have more control over what is happening, and you can even drop the cap_sys_chroot privilege after you call it, so successive calls to chroot in your program will fail.
A custom chrooter isn't at all hard to write:
#define _BSD_SOURCE
#include <stdio.h>
#include <unistd.h>
const char newroot[]="/path/to/chroot";
int main(int c, char **v, char **e) {
int rc; const char *m;
if ( (m="chdir" ,rc=chdir(newroot)) == 0
&& (m="chroot",rc=chroot(newroot)) == 0
&& (m="setuid",rc=setuid(getuid())) == 0 )
m="execve", execve(v[1],v+2,e);
perror(m);
return 1;
}
Make that setuid root and owned by a custom group you add your favored user to (and no 'other' access).
You could use Linux Containers to create a chroot environment that is in a totally different namespace (IPC, filesytem, and even network)
There is even LXD which is able to manage the creation of image-based containers and configure them to run as unprivileged users so that if the untrusted code manages to somehow escape the container, it will only be able to execute code as the unprivileged user and not as the system's root.
Search 'Linux Containers' and 'LXD' on your favorite search engine ;)
These days chrooting without root-permissions is possible with unshare command provided by mount namespaces.
Plain Unshare
Suppose you want to chroot into ~/Projects/my-backup directory, and run inside it the ~/Projects/my-backup/bin/bash binary . So you run:
$ unshare -mr chroot ~/Projects/my-backup/ /bin/bash
Here:
-m means you can use mount --bind inside the new chroot (note that mounts will not be visible to the outside world, only to your chroot)
-r makes it look as if you are root inside the chroot
chroot … is the usual chroot command.
Possible pitfalls:
Make sure you have environment variables set correctly. For example, upon chrooting into an Ubuntu from Archlinux I was getting errors like bash: ls: command not found. Turned out, my $PATH did not contain /bin/ (on Archlinux it's a symlink to /usr/bin/), so I had to run:
PATH=$PATH:/bin/ unshare -mr chroot ~/Projects/my-backup/ /bin/bash
Note that /proc or /dev filesystems won't get populated, so running a binary that requires them will fail. There is a --mount-proc option, but it doesn't seem to be accessible to a non-root user.
chown won't work unless you do some complicated setup with newuidmap and newgidmap commands.
Buildah Unshare
This has advantage compared to plain unshare in that it takes care of the needed setup for chown command to start working. You only need to make sure you have defined the ranges in /etc/subuid and /etc/subgid for your user.
You run it as:
$ buildah unshare chroot ~/Projects/my-backup/ /bin/bash

Resources