2
 jordan zu$  git status
On branch origin/features
Your branch is up to date with 'remotes/origin/features'.
nothing to commit, working tree clean

 jordan zu$  git checkout master
error: unable to unlink old 'api_rest/vendor/....php': Permission denied
fatal: cannot create directory at 'api_rest/vendor/...php': Permission denied

 jordan zu$  git status
On branch origin/features
Your branch is up to date with 'remotes/origin/features'.

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
   ---- 100's of deleted/modified files ---

 jordan zu$  git branch
  master
* origin/features
  ^^^ still on origin/features; but index is now changed!

So, I was on a 'features' branch, did a 'git checkout master', but it failed. After it failed, I ran 'git status', and now my index is full of changes and untracked files. So, this is what I think happened: git checkout got as far as it could with modifying the worktree, but once it hit an error, it quit, and didn't update HEAD. Instead of reverting the worktree to before it was ran, it just quits.

Am I right on my thinking? Is that what is happening?

Sub-question; part of the problem is that when I start my docker services, they modify some of the worktree and leave directories and files that are owned by 'root', and this is where git checkout runs into problems. Is there a standard way to handle a situation like that? Can I map the docker user to the owner of the worktree somehow?

Thank you for your help.

Jordan
  • 194
  • 1
  • 12
  • I have edited my answer with additional elements regarding Docker user namespace mapping. – VonC Feb 06 '22 at 21:25

1 Answers1

2

git checkout got as far as it could with modifying the worktree, but once it hit an error, it quit, and didn't update HEAD. Instead of reverting the worktree to before it was ran, it just quits.

I think it is indeed what happened.
A git status dispays:

  • paths that have differences between the index file and the current HEAD commit,
  • paths that have differences between the working tree and the index file,
  • and paths in the working tree that are not tracked by Git

If HEAD is still as feature, while the index et working tree start to reflect master, you would see all those differences.

By the way, using git switch master would be the modern equivalent of git checkout (when switching branch, hence the switch command

part of the problem is that when I start my docker services, they modify some of the worktree and leave directories and files that are owned by 'root', and this is where git checkout runs into problems.

Can I map the docker user to the owner of the worktree somehow?

Yes, you could Isolate containers with a user namespace

The best way to prevent privilege-escalation attacks from within a container is to configure your container’s applications to run as unprivileged users.

For containers whose processes must run as the root user within the container, you can re-map this user to a less-privileged user on the Docker host.
The mapped user is assigned a range of UIDs which function within the namespace as normal UIDs from 0 to 65536, but have no privileges on the host machine itself.

The general principle:

About remapping and subordinate user and group IDs

The remapping itself is handled by two files: /etc/subuid and /etc/subgid.
Each file works the same, but one is concerned with the user ID range, and the other with the group ID range.

Consider the following entry in /etc/subuid:

testuser:231072:65536

This means that testuser is assigned a subordinate user ID range of 231072 and the next 65536 integers in sequence.

  • UID 231072 is mapped within the namespace (within the container, in this case) as UID 0 (root).
  • UID 231073 is mapped as UID 1, and so forth.

If a process attempts to escalate privilege outside of the namespace, the process is running as an unprivileged high-number UID on the host, which does not even map to a real user.
This means the process has no privileges on the host system at all.

In your case, that would mean the user root inside your container could write files outside the container as your current user account uid/gid.

What I usually ask is:

cat  /etc/docker/daemon.json
{
  "data-root": "/project/docker-root",
  "storage-driver": "overlay2",
  "userns-remap": "myUserApp1:myGroup"  =====
}

sysctl -w user.max_user_namespaces=15000
systemctl restart docker
systemctl status docker
cat /proc/sys/user/max_user_namespaces

(On user.max_user_namespaces, see "Docker error process_linux.go:319: getting the final child's pid from pipe caused "EOF": unknown", and moby/moby issue 40835)

With:

cat /etc/subuid
myUserApp1:44581:65536
cat /etc/subgid
myGroup:14220:65536

(Assuming the current user account myUserApp1:MyGroup is has the uuid/guid 44581:14220)

Sometimes (for a Docker JBoss/wildfly image for instance, which runs as 1000:1000 by default), I have to ask for /etc/subuid with 43581 (instead of 44581), because that way, the user 1000 inside the container is mapped to 44581 outside (43581+1000).

Big drawback: That means you can only map one internal container user to one external host user.
If you have another container which runs with 1000:1000, it would be mapped to the same myUserApp1, even though you might have another service account myUserApp2 for this second container persistent data.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250