Commit e8b89a61 authored by Ondřej Zajíček's avatar Ondřej Zajíček

Update and document the privilege restriction.

parent 1bc26957
......@@ -145,10 +145,42 @@ options. The most important ones are:
<tag>-s <m/name of communication socket/</tag>
use given filename for a socket for communications with the client, default is <it/prefix/<file>/var/run/bird.ctl</file>.
<tag>-u <m/user/</tag>
drop privileges and use that user ID, see the next section for details.
<tag>-g <m/group/</tag>
use that group ID, see the next section for details.
<p>BIRD writes messages about its work to log files or syslog (according to config).
<p>BIRD, as a routing daemon, uses several privileged operations (like
setting routing table and using raw sockets). Traditionally, BIRD is
executed and runs with root privileges, which may be prone to security
problems. The recommended way is to use a privilege restriction
(options <cf/-u/, <cf/-g/). In that case BIRD is executed with root
privileges, but it changes its user and group ID to an unprivileged
ones, while using Linux capabilities to retain just required
privileges (capabilities CAP_NET_*). Note that the control socket is
created before the privileges are dropped, but the config file is read
after that. The privilege restriction is not implemented in BSD port
of BIRD.
<p>A nonprivileged user (as an argument to <cf/-u/ options) may be the
user <cf/nobody/, but it is suggested to use a new dedicated user
account (like <cf/bird/). The similar considerations apply for
the group option, but there is one more condition -- the users
in the same group can use <file/birdc/ to control BIRD.
<p>Finally, there is a possibility to use external tools to run BIRD in
an environment with restricted privileges. This may need some
configuration, but it is generally easy -- BIRD needs just the
standard library, privileges to read the config file and create the
control socket and the CAP_NET_* capabilities.
<chapt>About routing tables
<p>BIRD has one or more routing tables which may or may not be
......@@ -48,15 +48,20 @@ drop_uid(uid_t uid)
/* change effective user ID to be able to switch to that
user ID completely after dropping CAP_SETUID */
if (seteuid(uid) < 0)
die("seteuid: %m");
/* restrict the capabilities */
if (set_capabilities(caps) < 0)
die("capset: %m");
/* keep the capabilities after dropping root ID */
if (prctl(PR_SET_KEEPCAPS, 1) < 0)
die("prctl: %m");
/* completely switch to the unprivileged user ID */
if (setresuid(uid, uid, uid) < 0)
die("setresuid: %m");
......@@ -383,7 +383,7 @@ cli_connect(sock *s, int size UNUSED)
static void
cli_init_unix(uid_t use_uid, gid_t use_gid)
sock *s;
......@@ -393,6 +393,13 @@ cli_init_unix(void)
s->rx_hook = cli_connect;
s->rbsize = 1024;
sk_open_unix(s, path_control_socket);
if (use_uid || use_gid)
if (chown(path_control_socket, use_uid, use_gid) < 0)
die("chown: %m");
if (chmod(path_control_socket, 0660) < 0)
die("chmod: %m");
......@@ -503,9 +510,13 @@ get_uid(const char *s)
struct passwd *pw;
char *endptr;
long int rv;
if (!s)
return 0;
errno = 0;
long int rv = strtol(s, &endptr, 10);
rv = strtol(s, &endptr, 10);
if (!errno && !*endptr)
return rv;
......@@ -522,9 +533,13 @@ get_gid(const char *s)
struct group *gr;
char *endptr;
long int rv;
if (!s)
return 0;
errno = 0;
long int rv = strtol(s, &endptr, 10);
rv = strtol(s, &endptr, 10);
if (!errno && !*endptr)
return rv;
......@@ -601,24 +616,26 @@ main(int argc, char **argv)
log_switch(debug_flag, NULL, NULL);
if (use_group)
if (use_user)
if (!parse_and_exit)
uid_t use_uid = get_uid(use_user);
gid_t use_gid = get_gid(use_group);
if (!parse_and_exit)
cli_init_unix(use_uid, use_gid);
if (use_gid)
if (use_uid)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment