diff mbox

[ovs-dev,v3,05/10] lib/daemon: all daemons works with the --user option

Message ID 1442271254-27897-6-git-send-email-azhou@nicira.com
State Changes Requested
Headers show

Commit Message

Andy Zhou Sept. 14, 2015, 10:54 p.m. UTC
All daemons launched by root can drop their privilege using
--user option. See man page update form more details.

Signed-off-by: Andy Zhou <azhou@nicira.com>
---
 NEWS                                      |  1 +
 lib/daemon.man                            | 10 ++++++++++
 ovn/controller-vtep/ovn-controller-vtep.c |  1 +
 ovn/northd/ovn-northd.c                   |  1 +
 ovsdb/ovsdb-client.c                      |  4 +++-
 ovsdb/ovsdb-server.c                      |  1 +
 tests/test-jsonrpc.c                      |  3 ++-
 tests/test-netflow.c                      |  4 ++--
 tests/test-sflow.c                        |  1 +
 utilities/ovs-ofctl.c                     |  2 ++
 utilities/ovs-testcontroller.c            |  4 +++-
 vswitchd/ovs-vswitchd.c                   | 15 +++++++++++++++
 12 files changed, 42 insertions(+), 5 deletions(-)

Comments

Ansis Atteka Sept. 18, 2015, 6:02 a.m. UTC | #1
On Mon, Sep 14, 2015 at 3:54 PM, Andy Zhou <azhou@nicira.com> wrote:
> All daemons launched by root can drop their privilege using
s/privilege/privileges
> --user option. See man page update form more details.
s/form/for
>
> Signed-off-by: Andy Zhou <azhou@nicira.com>
> ---
>  NEWS                                      |  1 +
>  lib/daemon.man                            | 10 ++++++++++
>  ovn/controller-vtep/ovn-controller-vtep.c |  1 +
>  ovn/northd/ovn-northd.c                   |  1 +
>  ovsdb/ovsdb-client.c                      |  4 +++-
>  ovsdb/ovsdb-server.c                      |  1 +
>  tests/test-jsonrpc.c                      |  3 ++-
>  tests/test-netflow.c                      |  4 ++--
>  tests/test-sflow.c                        |  1 +
>  utilities/ovs-ofctl.c                     |  2 ++
>  utilities/ovs-testcontroller.c            |  4 +++-
>  vswitchd/ovs-vswitchd.c                   | 15 +++++++++++++++
>  12 files changed, 42 insertions(+), 5 deletions(-)
>
> diff --git a/NEWS b/NEWS
> index ca22c8e..ee4dc2a 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -21,6 +21,7 @@ Post-v2.4.0
>       targets to run a new system testsuite.  These tests can be run inside
>       a Vagrant box.  See INSTALL.md for details
>     - Dropped support for GRE64 tunnel.
> +   - Added --user option to all daemons
>
>
>  v2.4.0 - 20 Aug 2015
> diff --git a/lib/daemon.man b/lib/daemon.man
> index 4ab9823..093b08a 100644
> --- a/lib/daemon.man
> +++ b/lib/daemon.man
> @@ -50,3 +50,13 @@ core dumps into the current working directory and the root directory
>  is not a good directory to use.
>  .IP
>  This option has no effect when \fB\-\-detach\fR is not specified.
> +.
> +.TP
> +\fB\-\-user\fR
> +Causes \fB\*(PN\fR to run as a non root user specified in "user:group", thus
> +dropping all root privileges. Short forms "user" and ":group" are also
> +allowed, with current user or group are assumed respectively. Only daemons
> +started by the root user accepts this argument.
> +.IP
> +On Linux, daemons need to access kernel datapath, such as ovs-vswitchd,
> +will be granted CAP_NET_ADMIN capability before dropping root privileges.
> diff --git a/ovn/controller-vtep/ovn-controller-vtep.c b/ovn/controller-vtep/ovn-controller-vtep.c
> index b54b29d..013dc08 100644
> --- a/ovn/controller-vtep/ovn-controller-vtep.c
> +++ b/ovn/controller-vtep/ovn-controller-vtep.c
> @@ -63,6 +63,7 @@ main(int argc, char *argv[])
>      parse_options(argc, argv);
>      fatal_ignore_sigpipe();
>
> +    daemon_become_new_user(false);
>      daemonize_start();
>
>      retval = unixctl_server_create(NULL, &unixctl);
> diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
> index 0f57e58..8e16e0d 100644
> --- a/ovn/northd/ovn-northd.c
> +++ b/ovn/northd/ovn-northd.c
> @@ -1167,6 +1167,7 @@ main(int argc, char *argv[])
>      vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
>      parse_options(argc, argv);
>
> +    daemon_become_new_user(false);
>      daemonize_start();
>
>      retval = unixctl_server_create(NULL, &unixctl);
> diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c
> index 575cf91..8bf7ce7 100644
> --- a/ovsdb/ovsdb-client.c
> +++ b/ovsdb/ovsdb-client.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
> + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -95,6 +95,8 @@ main(int argc, char *argv[])
>          ovs_fatal(0, "missing command name; use --help for help");
>      }
>
> +    daemon_become_new_user(false);
> +
>      for (command = get_all_commands(); ; command++) {
>          if (!command->name) {
>              VLOG_FATAL("unknown command '%s'; use --help for help",
> diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
> index 4088d85..91750a7 100644
> --- a/ovsdb/ovsdb-server.c
> +++ b/ovsdb/ovsdb-server.c
> @@ -221,6 +221,7 @@ main(int argc, char *argv[])
>      process_init();
>
>      parse_options(&argc, &argv, &remotes, &unixctl_path, &run_command);
> +    daemon_become_new_user(false);
>
>      /* Create and initialize 'config_tmpfile' as a temporary file to hold
>       * ovsdb-server's most basic configuration, and then save our initial
> diff --git a/tests/test-jsonrpc.c b/tests/test-jsonrpc.c
> index f66dc65..f1da341 100644
> --- a/tests/test-jsonrpc.c
> +++ b/tests/test-jsonrpc.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
> + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -182,6 +182,7 @@ do_listen(struct ovs_cmdl_context *ctx)
>          ovs_fatal(error, "could not listen on \"%s\"", ctx->argv[1]);
>      }
>
> +    daemon_become_new_user(false);
>      daemonize();
>
>      rpcs = NULL;
> diff --git a/tests/test-netflow.c b/tests/test-netflow.c
> index 631d7a2..9b4fbc9 100644
> --- a/tests/test-netflow.c
> +++ b/tests/test-netflow.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
> + * Copyright (c) 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -188,7 +188,7 @@ test_netflow_main(int argc, char *argv[])
>                    "(use --help for help)");
>      }
>      target = argv[optind];
> -
> +    daemon_become_new_user(false);
>      sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0, true);
>      if (sock < 0) {
>          ovs_fatal(0, "%s: failed to open (%s)", argv[1], ovs_strerror(-sock));
> diff --git a/tests/test-sflow.c b/tests/test-sflow.c
> index 6f90ebf..dd21af8 100644
> --- a/tests/test-sflow.c
> +++ b/tests/test-sflow.c
> @@ -677,6 +677,7 @@ test_sflow_main(int argc, char *argv[])
>      }
>      target = argv[optind];
>
> +    daemon_become_new_user(false);
>      sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0, true);
>      if (sock < 0) {
>          ovs_fatal(0, "%s: failed to open (%s)", target, ovs_strerror(-sock));
> diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
> index 75e84e2..f7e4acb 100644
> --- a/utilities/ovs-ofctl.c
> +++ b/utilities/ovs-ofctl.c
> @@ -130,6 +130,8 @@ main(int argc, char *argv[])
>      fatal_ignore_sigpipe();
>      ctx.argc = argc - optind;
>      ctx.argv = argv + optind;
> +
> +    daemon_become_new_user(false);
>      ovs_cmdl_run_command(&ctx, get_all_commands());
>      return 0;
>  }
> diff --git a/utilities/ovs-testcontroller.c b/utilities/ovs-testcontroller.c
> index 3d59adb..55942f0 100644
> --- a/utilities/ovs-testcontroller.c
> +++ b/utilities/ovs-testcontroller.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2015 Nicira, Inc.
>   *
>   * Licensed under the Apache License, Version 2.0 (the "License");
>   * you may not use this file except in compliance with the License.
> @@ -113,6 +113,8 @@ main(int argc, char *argv[])
>                    "use --help for usage");
>      }
>
> +    daemon_become_new_user(false);
> +
>      n_switches = n_listeners = 0;
>      for (i = optind; i < argc; i++) {
>          const char *name = argv[i];
> diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c
> index 4fe479e..5099806 100644
> --- a/vswitchd/ovs-vswitchd.c
> +++ b/vswitchd/ovs-vswitchd.c
> @@ -69,6 +69,7 @@ main(int argc, char *argv[])
>      char *remote;
>      bool exiting;
>      int retval;
> +    bool access_kernel_datapath = false;
>
>      set_program_name(argv[0]);
>      retval = dpdk_init(argc,argv);
> @@ -82,6 +83,20 @@ main(int argc, char *argv[])
>      ovs_cmdl_proctitle_init(argc, argv);
>      service_start(&argc, &argv);
>      remote = parse_options(argc, argv, &unixctl_path);
> +    /* Drop root privileges if --user option is specifed.
> +     *
> +     * On linux platforms that runs kernel datapath, we will
s/platforms/platform or s/runs/run
> +     * drop all privileges, execpt CAP_NET_ADMIN capabilities.
s/execpt/except
> +     *
> +     * The goal is to increase system security that in the event
> +     * ovs-vswitchd is somehow compromised, the process itself
> +     * does not have all root capabilities.
> +     */
> +#if __linux__ || defined _WIN32
> +    access_kernel_datapath = true;
Shouldn't you simply check for __linux__ here without || _WIN32?
Perhaps I am simply missing something.
> +#endif
> +    daemon_become_new_user(access_kernel_datapath);
> +
>      fatal_ignore_sigpipe();
>      ovsrec_init();
>
> --
> 1.9.1
>
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev
Ben Pfaff Sept. 18, 2015, 7:53 p.m. UTC | #2
On Mon, Sep 14, 2015 at 03:54:09PM -0700, Andy Zhou wrote:
> All daemons launched by root can drop their privilege using
> --user option. See man page update form more details.
> 
> Signed-off-by: Andy Zhou <azhou@nicira.com>

What worries me about this is that it relies on developers to remember
to add a call to daemon_become_new_user() to every daemon.  If we forget
one, it's a security hole: --user will be silently ignored.

Is it possible to integrate daemon_become_new_user() into some other
function that has to be called for daemonization to work?  For example,
can we integrate it into daemon_start()?  Or can we at least avoid the
security hole by, say, aborting in daemonize_complete() if
daemon_become_new_user() hasn't been called?
Andy Zhou Sept. 18, 2015, 11:16 p.m. UTC | #3
On Fri, Sep 18, 2015 at 12:53 PM, Ben Pfaff <blp@nicira.com> wrote:
> On Mon, Sep 14, 2015 at 03:54:09PM -0700, Andy Zhou wrote:
>> All daemons launched by root can drop their privilege using
>> --user option. See man page update form more details.
>>
>> Signed-off-by: Andy Zhou <azhou@nicira.com>
>
> What worries me about this is that it relies on developers to remember
> to add a call to daemon_become_new_user() to every daemon.  If we forget
> one, it's a security hole: --user will be silently ignored.
>
> Is it possible to integrate daemon_become_new_user() into some other
> function that has to be called for daemonization to work?  For example,
> can we integrate it into daemon_start()?  Or can we at least avoid the
> security hole by, say, aborting in daemonize_complete() if
> daemon_become_new_user() hasn't been called?

Integrating this function into daemon_start() seems to be an
attractive option. Let me try to implement this. If not, I will fall back
to abort in daemonize_complete().
diff mbox

Patch

diff --git a/NEWS b/NEWS
index ca22c8e..ee4dc2a 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,7 @@  Post-v2.4.0
      targets to run a new system testsuite.  These tests can be run inside
      a Vagrant box.  See INSTALL.md for details
    - Dropped support for GRE64 tunnel.
+   - Added --user option to all daemons
 
 
 v2.4.0 - 20 Aug 2015
diff --git a/lib/daemon.man b/lib/daemon.man
index 4ab9823..093b08a 100644
--- a/lib/daemon.man
+++ b/lib/daemon.man
@@ -50,3 +50,13 @@  core dumps into the current working directory and the root directory
 is not a good directory to use.
 .IP
 This option has no effect when \fB\-\-detach\fR is not specified.
+.
+.TP
+\fB\-\-user\fR
+Causes \fB\*(PN\fR to run as a non root user specified in "user:group", thus
+dropping all root privileges. Short forms "user" and ":group" are also
+allowed, with current user or group are assumed respectively. Only daemons
+started by the root user accepts this argument.
+.IP
+On Linux, daemons need to access kernel datapath, such as ovs-vswitchd,
+will be granted CAP_NET_ADMIN capability before dropping root privileges.
diff --git a/ovn/controller-vtep/ovn-controller-vtep.c b/ovn/controller-vtep/ovn-controller-vtep.c
index b54b29d..013dc08 100644
--- a/ovn/controller-vtep/ovn-controller-vtep.c
+++ b/ovn/controller-vtep/ovn-controller-vtep.c
@@ -63,6 +63,7 @@  main(int argc, char *argv[])
     parse_options(argc, argv);
     fatal_ignore_sigpipe();
 
+    daemon_become_new_user(false);
     daemonize_start();
 
     retval = unixctl_server_create(NULL, &unixctl);
diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c
index 0f57e58..8e16e0d 100644
--- a/ovn/northd/ovn-northd.c
+++ b/ovn/northd/ovn-northd.c
@@ -1167,6 +1167,7 @@  main(int argc, char *argv[])
     vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN);
     parse_options(argc, argv);
 
+    daemon_become_new_user(false);
     daemonize_start();
 
     retval = unixctl_server_create(NULL, &unixctl);
diff --git a/ovsdb/ovsdb-client.c b/ovsdb/ovsdb-client.c
index 575cf91..8bf7ce7 100644
--- a/ovsdb/ovsdb-client.c
+++ b/ovsdb/ovsdb-client.c
@@ -1,5 +1,5 @@ 
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -95,6 +95,8 @@  main(int argc, char *argv[])
         ovs_fatal(0, "missing command name; use --help for help");
     }
 
+    daemon_become_new_user(false);
+
     for (command = get_all_commands(); ; command++) {
         if (!command->name) {
             VLOG_FATAL("unknown command '%s'; use --help for help",
diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
index 4088d85..91750a7 100644
--- a/ovsdb/ovsdb-server.c
+++ b/ovsdb/ovsdb-server.c
@@ -221,6 +221,7 @@  main(int argc, char *argv[])
     process_init();
 
     parse_options(&argc, &argv, &remotes, &unixctl_path, &run_command);
+    daemon_become_new_user(false);
 
     /* Create and initialize 'config_tmpfile' as a temporary file to hold
      * ovsdb-server's most basic configuration, and then save our initial
diff --git a/tests/test-jsonrpc.c b/tests/test-jsonrpc.c
index f66dc65..f1da341 100644
--- a/tests/test-jsonrpc.c
+++ b/tests/test-jsonrpc.c
@@ -1,5 +1,5 @@ 
 /*
- * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -182,6 +182,7 @@  do_listen(struct ovs_cmdl_context *ctx)
         ovs_fatal(error, "could not listen on \"%s\"", ctx->argv[1]);
     }
 
+    daemon_become_new_user(false);
     daemonize();
 
     rpcs = NULL;
diff --git a/tests/test-netflow.c b/tests/test-netflow.c
index 631d7a2..9b4fbc9 100644
--- a/tests/test-netflow.c
+++ b/tests/test-netflow.c
@@ -1,5 +1,5 @@ 
 /*
- * Copyright (c) 2011, 2012, 2013, 2014 Nicira, Inc.
+ * Copyright (c) 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -188,7 +188,7 @@  test_netflow_main(int argc, char *argv[])
                   "(use --help for help)");
     }
     target = argv[optind];
-
+    daemon_become_new_user(false);
     sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0, true);
     if (sock < 0) {
         ovs_fatal(0, "%s: failed to open (%s)", argv[1], ovs_strerror(-sock));
diff --git a/tests/test-sflow.c b/tests/test-sflow.c
index 6f90ebf..dd21af8 100644
--- a/tests/test-sflow.c
+++ b/tests/test-sflow.c
@@ -677,6 +677,7 @@  test_sflow_main(int argc, char *argv[])
     }
     target = argv[optind];
 
+    daemon_become_new_user(false);
     sock = inet_open_passive(SOCK_DGRAM, target, 0, NULL, 0, true);
     if (sock < 0) {
         ovs_fatal(0, "%s: failed to open (%s)", target, ovs_strerror(-sock));
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 75e84e2..f7e4acb 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -130,6 +130,8 @@  main(int argc, char *argv[])
     fatal_ignore_sigpipe();
     ctx.argc = argc - optind;
     ctx.argv = argv + optind;
+
+    daemon_become_new_user(false);
     ovs_cmdl_run_command(&ctx, get_all_commands());
     return 0;
 }
diff --git a/utilities/ovs-testcontroller.c b/utilities/ovs-testcontroller.c
index 3d59adb..55942f0 100644
--- a/utilities/ovs-testcontroller.c
+++ b/utilities/ovs-testcontroller.c
@@ -1,5 +1,5 @@ 
 /*
- * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2015 Nicira, Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -113,6 +113,8 @@  main(int argc, char *argv[])
                   "use --help for usage");
     }
 
+    daemon_become_new_user(false);
+
     n_switches = n_listeners = 0;
     for (i = optind; i < argc; i++) {
         const char *name = argv[i];
diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c
index 4fe479e..5099806 100644
--- a/vswitchd/ovs-vswitchd.c
+++ b/vswitchd/ovs-vswitchd.c
@@ -69,6 +69,7 @@  main(int argc, char *argv[])
     char *remote;
     bool exiting;
     int retval;
+    bool access_kernel_datapath = false;
 
     set_program_name(argv[0]);
     retval = dpdk_init(argc,argv);
@@ -82,6 +83,20 @@  main(int argc, char *argv[])
     ovs_cmdl_proctitle_init(argc, argv);
     service_start(&argc, &argv);
     remote = parse_options(argc, argv, &unixctl_path);
+    /* Drop root privileges if --user option is specifed.
+     *
+     * On linux platforms that runs kernel datapath, we will
+     * drop all privileges, execpt CAP_NET_ADMIN capabilities.
+     *
+     * The goal is to increase system security that in the event
+     * ovs-vswitchd is somehow compromised, the process itself
+     * does not have all root capabilities.
+     */
+#if __linux__ || defined _WIN32
+    access_kernel_datapath = true;
+#endif
+    daemon_become_new_user(access_kernel_datapath);
+
     fatal_ignore_sigpipe();
     ovsrec_init();