1

Is it normal behavior, or a bug, that when I run ss -nltp, I only see the process/pid information if the user I am running ss -nltp as is the same user as the listening process?

$ docker run -it --rm tianon/network-toolbox
root@bc058746626a:/# apt update
...
root@bc058746626a:/# apt install gosu
...
root@bc058746626a:/# nc -l 4444
[... check ss in another terminal]
^C
root@bc058746626a:/# gosu nobody nc -l 4444
....


$ docker exec -it admiring_keller bash
$ # both running as root
root@bc058746626a:/# ss -nltp
State     Recv-Q     Send-Q         Local Address:Port         Peer Address:Port    
LISTEN    0          1                    0.0.0.0:4444              0.0.0.0:*        users:(("nc",pid=325,fd=3))
$ # process running as nobody, ss as root
root@bc058746626a:/# ss -nltp
State     Recv-Q     Send-Q         Local Address:Port         Peer Address:Port    
LISTEN    0          1                    0.0.0.0:4444              0.0.0.0:*       
$ # process still as nobody , ss as nobody
root@bc058746626a:/# gosu nobody ss -nltp
State     Recv-Q     Send-Q         Local Address:Port         Peer Address:Port    
LISTEN    0          1                    0.0.0.0:4444              0.0.0.0:*        users:(("nc",pid=343,fd=3))
root@bc058746626a:/# exit
$ # process still as nobody , ss as nobody
$ docker exec -it --user nobody admiring_keller bash
nobody@bc058746626a:/$ ss -nltp
State     Recv-Q     Send-Q         Local Address:Port         Peer Address:Port    
LISTEN    0          1                    0.0.0.0:4444              0.0.0.0:*        users:(("nc",pid=343,fd=3))
nobody@bc058746626a:/$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.0   4764  4124 pts/0    SNs  16:42   0:00 bash --login -i
nobody       343  0.0  0.0   3204   864 pts/0    SN+  16:45   0:00 nc -l 4444
nobody       369  0.0  0.0   3872  3152 pts/1    SNs  16:50   0:00 bash
nobody       377  0.0  0.0   7644  2708 pts/1    RN+  16:54   0:00 ps aux

Related: https://stackoverflow.com/questions/68085747/why-would-a-process-not-be-associated-with-a-port-when-using-gosu

0

For a normal user that's normal behavior. To be able to associate the socket to a process, at some point, /proc/<pid>/fd/ must be read by ss. Only the same user or a privileged process (including running as root) has access to this.

Here's an strace excerpt about what is happening outside of Docker.

# runuser -u test -- sh -c 'echo $$; exec socat tcp4-listen:5555,reuseaddr -'
445406

and beside:

user@host$ strace ss -tlnp sport == 5555 2>&1 |egrep -w '445406|^LISTEN'
openat(AT_FDCWD, "/proc/445406/attr/current", O_RDONLY|O_CLOEXEC) = 4
openat(AT_FDCWD, "/proc/445406/fd/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 EACCES (Permission denied)
LISTEN    0         5                  0.0.0.0:5555             0.0.0.0:*       

The unconstrained root user wouldn't get EACCESS, would have access to needed information and would be able to display the PID in the end.

But Docker doesn't run as normal root user: some capabilities (a capability is a piece of root "powers". root by default has all of them) were removed. And because of this root in the container gets the same error as a normal user, doesn't have access to the needed information to associate the socket to a process.

root@1589d8b38814:/# apt install libcap2-bin
[...]
oot@1589d8b38814:/# cat /proc/$$/status|grep ^Cap
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000
root@1589d8b38814:/# capsh --decode=00000000a80425fb
0x00000000a80425fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,
cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,
cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap

While the actual root user or when running the Docker container in privileged mode (--privileged):

root@cce7fc1de1c3:/# cat /proc/$$/status |grep ^Cap
CapInh: 0000003fffffffff
CapPrm: 0000003fffffffff
CapEff: 0000003fffffffff
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
root@cce7fc1de1c3:/# capsh --decode=0000003fffffffff
0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,
cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,
cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,
cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,
cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,
cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,
cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,
cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,
cap_block_suspend,cap_audit_read

Much more.

Here dropping cap_sys_ptrace (which affects access in /proc) is enough to derail it. Note that an unprivileged Docker container doesn't give cap_sys_ptrace to its root user.

With socat running as nobody with pid 392 and a privileged docker root user beside:

root@df29c4a57b3f:/# capsh --inh= --caps= -- -c 'ss -tlnp sport == 5555'
State     Recv-Q    Send-Q       Local Address:Port        Peer Address:Port    
LISTEN    0         5                  0.0.0.0:5555             0.0.0.0:*        users:(("socat",pid=392,fd=5))
root@df29c4a57b3f:/# capsh --drop=cap_sys_ptrace --inh= --caps= -- -c 'ss -tlnp sport == 5555'
State     Recv-Q    Send-Q       Local Address:Port        Peer Address:Port    
LISTEN    0         5                  0.0.0.0:5555             0.0.0.0:*       

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.