7

Basically, What is going on here and what am I not understanding?

I have a set of subuids for my user. I want to chown a file to specific subuid which is part of this user's allocation

administrator@host:/home/administrator$ cat /etc/subuid
root:100000:65536
administrator:165536:65536
administrator:1000000:9000001

administrator@host:/home/administrator$ cat /etc/subgid
root:100000:65536
administrator:165536:65536
administrator:1000000:9000001

Trying to chown this file is failing despite this subuid being part of the allocation.

administrator@host:/home/administrator$ ls -lhat
...
-rw-rw-r-- 1 administrator administrator  229 Aug  2 13:00 file
drwxrwxr-x 7 administrator administrator 4.0K Aug  2 13:00 ..

administrator@host:/home/administrator$ chown 1500000:1500000 file
chown: changing ownership of 'file': Operation not permitted

administrator@host:/home/administrator$ stat file
  File: file
  Size: 229             Blocks: 8          IO Block: 4096   regular file
Device: 802h/2050d      Inode: 658357      Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/administrator)   Gid: ( 1004/administrator)
Access: 2018-08-02 13:00:36.529197108 +0000
Modify: 2018-08-02 13:00:36.529197108 +0000
Change: 2018-08-02 13:00:36.529197108 +0000
 Birth: -
administrator@host:/home/administrator$

However, I can remove the file as user, if I use sudo to chown it - but it shows as a write protected file when I do. This indicates I do in fact have permissions to modify files with this subuid.

administrator@host:~$ touch file
administrator@host:~$ chown 1500000:1500000 file
chown: changing ownership of 'file': Operation not permitted

administrator@host:~$ sudo chown 1500000:1500000 file    
administrator@host:~$ rm file
rm: remove write-protected regular empty file 'testfile.txt'?
administrator@host:~$

Can anyone explain the inner workings which is going on here? I've probably misunderstood something basic somewhere. I can't tag this as subuid because not enough rep, so I'll use uid.

Thanks!

TechnicalChaos
  • 133
  • 1
  • 8
  • @anx I'm using unprivileged lxc containers. I have a set of files that are located on the host and bind mounted inside a container. If the files on the host are owned by the unprivileged user, they are owned as `nobody` inside the container and therefore are read only. I need to set the correct subuid on those files so the container user can modify etc. Hope that makes sense. – TechnicalChaos Aug 08 '18 at 08:04
  • `Access: (0664/-rw-rw-r--) Uid: ( 1000/administrator) Gid: ( 1004/administrator)` Neither administrator:165536:65536, nor administrator:1000000:9000001 owns the file. However @bgtvfr's answer tells you the answer to your "What is going on here and what am I not understanding" question. Non-privileged user cannot assign ownership of a file to person or group for which they do not have privileges. – Jeter-work Aug 09 '18 at 22:02

5 Answers5

12

Subuids aren't meant to work the way you expect them to work. They are designed to map UIDs in a user namespace to different UIDs outside that namespace, which comes in handy (and actually was designed) for containers.

However, a process still can have only one UID set (user namespace), and users are not permitted to change ownership of files, for obvious security reasons. It doesn't matter, as far as the process itself is concerned, if the user is actually someone else outside the namespace.

This is why the chown command fails: it doesn't matter if you could have some other UID, should the namespace was different, at that moment, you don't have that UID, and therefore, you can't change the ownership of any files (since you're not root).

As of why can you remove the file: it has actually nothing to do with subuids, instead, it all depends on you having the ownership of the directory the file resides in. Since file deletion changes the directory, and not the file itself, if you can write the directory, you can remove any files from that (except for "sticky" directories).

Lacek
  • 7,233
  • 24
  • 28
  • I did not know that last part. I can delete files that I can't write to. It feels messed up. I could make other people loose access to their files because we both have the permission to write to the file which keeps its location. Makes sense, but feels wrong. Explains why /tmp has to have a sticky bit though. – timuçin Mar 28 '21 at 05:11
7

There is a program lxc-usernsexec that comes along with lxc. This allows you to remap user id's using the maps /etc/subuid and /etc/subgid.

Specifically, you can do the following.

  1. lxc-usernsexec -- touch /tmp/test
  2. ls -l /tmp/test will show that the file is owner:group the same as the first subuid:subgid pair in your map.
  3. rm /tmp/test should give an error since you do not currently have the right uid/gid.
  4. lxc-usernsexec -- rm /tmp/test should remove the file.

Hope this helps! The above probably requires various things setup for unprivileged LXC container use. In particular, I think /proc/sys/kernel/unprivileged_userns_clone should be 1.

Kapil
  • 221
  • 1
  • 2
  • Thanks! This is great! I'd give you the bounty but it was autoassigned whilst I was holidaying. At first glance I'm getting an error - `[pid 18428] write(2, ...failed to write mapping "newuidmap: ... Operation not permitted"` and `[pid 18429] setgid(0) = -1 EINVAL (Invalid argument)`. I've ensured that unprivileged_userns_clone is set to 1 but there's likely some other flag needs sorting. I can work with this. All in all though this seems to be the right tool for the job, which is what I was looking for, so thank you. – TechnicalChaos Aug 21 '18 at 08:49
  • thanks so much for this answer, I was still wrapping my head about the whole subuid/subgid thing, it really helps that a general purpose tool like this exists – wump Oct 19 '20 at 08:44
5

As a complement to @Kapil's answer, and since it may be difficult to install additional tools if you are not root, you can also use podman unshare (shipped with Podman) or rootlesskit (shipped with rootless Docker) as an alternative to lxc-usernsexec (shipped with LXC).

user2580621
  • 51
  • 1
  • 1
2

Your problem has nothing to do with subuid .

According to https://superuser.com/questions/697608/chown-operation-not-permitted

Non-privileged users (not root) cannot chown files to other user names. To use chown, a user must have the privileges of the target user. In other words, only root can give a file to another user.

bgtvfr
  • 1,262
  • 10
  • 20
  • 2
    Setuid and setgid are always cleared on chown. – RalfFriedl Aug 06 '18 at 18:22
  • 1
    "To use chown, a user must have the privileges of the target user." - I would have assumed that with subuids, the privileges of the target user are the same as the privileges of the user that has the subuids set against it? Essentially chowning to itself, just with a different uid. – TechnicalChaos Aug 08 '18 at 08:06
0

Many people will be encountering subuid/subgid issues related to docker/podman rootless or --userns. So here is a possible solution to your whoes. @user2580621 mentions the utility provided by the docker project called "rootlesskit". Podman has it's own solution for this as well I believe. rootlesskit comes with the rootless docker package from the docker project for all the major linux distros (it can also be downloaded but you can do your own research). Once you've got it installed. To use it you would issue, for example: rootlesskit -- chmod 1001:0. Keep in mind that the uid and gid you supply gets offset according to your /etc/sub[ug]id entry. It's referring to uid 1001 and group id 0 in your user namespace. On the local file you'll often find yourself needing to do this when a Dockerfile applies non-default directory ownership/permissions to a VOLUME and/or runs as non-root in the container and you want to bind that volume to a directory on your local file system. This becomes a problem because that local directory needs to be permissive enough to hold that volume. How do you do it?

A good example of this is the official mysql docker images. Reading the Dockerfile they create a mysql user (1001) and group (1001) and then proceed to install mysqld and chown mysql:root /var/lib/mysql and chmod 775 ... Lets assume your uid and gid on your workstation are 1000:1000. You create a folder called mysql-data in your home directory and by default it would be owned by your user and group with (likely) 755 permissions. Now you proceed to:

docker run -v "$HOME/mysql-data:/var/lib/mysql" ... mysql

You'll see often (unless the stars align) that mysql will fail to initialize due to a permission error. This is because /var/lib/mysql (as far as the container is concerned is owned by root:root with 755 permissions (remember that in your case 1000:1000 on host system is the equivalent 0:0 in the container). The mysql docker image runs USER mysql (ie. uid 1001/gid 1001) inside the container. When the container starts up it's attempting to initialize/create the files inside the /var/lib/mysql folder and it will lack the permissions to write that folder. So what is the fix? Using the info we learned from the Dockerfile we would simply:

rootlesskit -- chown 1001:0 $HOME/mysql-data
rootlesskit -- chmod 775 $HOME/mysql-data

If you look at the permissions on the local file system you'll see they are translated to your user namespace

Now when we run our docker image you will see it works perfectly.

Another way to see these permissions without reading through the Dockerfile would be to simply allow docker to create the container without a bind mount and give it a volume name like:

docker run ... mysql

Notice we don't have -v ... anymore. Now that the docker container is running you can:

docker exec -it mysql ls -lnd /var/lib/mysql

You'll see the corresponding 1001:0 uid/gid and 775 permissions on that folder. Now you can just stop/delete the container. You now have the info you need without needing to read through the Dockerfile.

Good luck!

Matthew Lenz
  • 281
  • 2
  • 7