Is there a way for non-root processes to bind to “privileged” ports on Linux?

后端 未结 24 1309
予麋鹿
予麋鹿 2020-11-22 02:04

It\'s very annoying to have this limitation on my development box, when there won\'t ever be any users other than me.

I\'m aware of the standard workarounds, but non

24条回答
  •  青春惊慌失措
    2020-11-22 02:59

    I know this is an old question, but now with recent (>= 4.3) kernels there is finally a good answer to this - ambient capabilities.

    The quick answer is to grab a copy of the latest (as-yet-unreleased) version of libcap from git and compile it. Copy the resulting progs/capsh binary somewhere (/usr/local/bin is a good choice). Then, as root, start your program with

    /usr/local/bin/capsh --keep=1 --user='your-service-user-name' \
        --inh='cap_net_bind_service' --addamb='cap_net_bind_service' \ 
        -- -c 'your-program'
    

    In order, we are

    • Declaring that when we switch users, we want to keep our current capability sets
    • Switching user & group to 'your-service-user-name'
    • Adding the cap_net_bind_service capability to the inherited & ambient sets
    • Forking bash -c 'your-command' (since capsh automatically starts bash with the arguments after --)

    There's a lot going on under the hood here.

    Firstly, we are running as root, so by default, we get a full set of capabilities. Included in this is the ability to switch uid & gid with the setuid and setgid syscalls. However, ordinarily when a program does this, it loses its set of capabilities - this is so that the old way of dropping root with setuid still works. The --keep=1 flag tells capsh to issue the prctl(PR_SET_KEEPCAPS) syscall, which disables the dropping of capabilities when changing user. The actual changing of users by capsh happens with the --user flag, which runs setuid and setgid.

    The next problem we need to solve is how to set capabilities in a way that carries on after we exec our children. The capabilities system has always had an 'inherited' set of capabilities, which is " a set of capabilities preserved across an execve(2)" [capabilities(7)]. Whilst this sounds like it solves our problem (just set the cap_net_bind_service capability to inherited, right?), this actually only applies for privileged processes - and our process is not privileged anymore, because we already changed user (with the --user flag).

    The new ambient capability set works around this problem - it is "a set of capabilities that are preserved across an execve(2) of a program that is not privileged." By putting cap_net_bind_service in the ambient set, when capsh exec's our server program, our program will inherit this capability and be able to bind listeners to low ports.

    If you're interested to learn more, the capabilities manual page explains this in great detail. Running capsh through strace is also very informative!

提交回复
热议问题