Reputation: 33
While playing with CentOs 8 on Docker container I found out, that outputs of who
and w
commands are always empty.
[root@9e24376316f1 ~]# who
[root@9e24376316f1 ~]# w
01:01:50 up 7:38, 0 users, load average: 0.00, 0.04, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
Even when I'm logged in as a different user in second terminal.
When I want to write
to this user it shows
[root@9e24376316f1 ~]# write test
write: test is not logged in
Is this because of Docker? Maybe it works in some way that disallow sessions to see each other? Or maybe that's some other issue. I would really appreciate some explanation.
Upvotes: 3
Views: 241
Reputation: 3758
These utilities obtain the information about current logins from the utmp file (/var/run/utmp
). You can easily check that in ordinary circumstances (e.g. on the desktop system) this file contains something like the following string (here qazer
is my login and tty7
is a TTY where my desktop environment runs):
$ cat /var/run/utmp
tty7:0qazer:0�o^�
while in the container this file is (usually) empty:
$ docker run -it centos
[root@5e91e9e1a28e /]# cat /var/run/utmp
[root@5e91e9e1a28e /]#
Why?
The utmp
file is usually modified by programs which authenticate the user and start the session: login(1)
, sshd(8)
, lightdm(1)
. However, the container engine cannot rely on them, as they may be absent in the container file system, so "logging in" and "executing on behalf of" is implemented in the most primitive and straightforward manner, avoiding relying on anything inside the container.
When any container is started or any command is exec
d inside it, the container engine just spawns the new process, arranges some security settings, calls setgid(2)
/setuid(2)
to forcibly (without any authentication) alter the process' UID/GID and then executes the required binary (the entry point, the command, and so on) within this process.
Say, I start the CentOS container running its main process on behalf of UID 42
:
docker run -it --user 42 centos
and then try to execute sleep 1000
inside it:
docker exec -it $CONTAINER_ID sleep 1000
The container engine will perform something like this:
[pid 10170] setgid(0) = 0
[pid 10170] setuid(42) = 0
...
[pid 10170] execve("/usr/bin/sleep", ["sleep", "1000"], 0xc000159740 /* 4 vars */) = 0
There will be no writes to /var/run/utmp
, thus it will remain empty, and who(1)
/w(1)
will not find any logins inside the container.
Upvotes: 2