coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] runcon: add --no-new-privs option


From: Sebastian Kisela
Subject: [PATCH] runcon: add --no-new-privs option
Date: Wed, 26 Apr 2017 15:57:12 +0200

* src/runcon.c: add --no-new-privs option to allow user to test
if given context grants more privileges to given command.
Uses no_new_privs bit introduced in Linux 3.5.
* tests/runcon/no-new-privs.sh: Add a test case.
* tests/local.mk: Reference the new test.
* NEWS: Mention the new feature
Discussed at https://bugzilla.redhat.com/1360903
---
 NEWS                         |  4 ++++
 src/runcon.c                 | 39 +++++++++++++++++++++++++++++++++++----
 tests/local.mk               |  1 +
 tests/runcon/no-new-privs.sh | 44
++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 84 insertions(+), 4 deletions(-)
 create mode 100755 tests/runcon/no-new-privs.sh

diff --git a/NEWS b/NEWS
index 72981b6..87d96cf 100644
--- a/NEWS
+++ b/NEWS
@@ -31,6 +31,10 @@ GNU coreutils NEWS
-*- outline -*-
   split supports a new --hex-suffixes[=from] option to create files with
   lower case hexadecimal suffixes, similar to the --numeric-suffixes
option.

+  runcon --no-new-privs now added for testing purposes. If the option is
used
+  runcon will not run a process in a context which has additional
privileges.
+  [uses no_new_privs bit added in Linux 3.5]
+

 * Noteworthy changes in release 8.27 (2017-03-08) [stable]

diff --git a/src/runcon.c b/src/runcon.c
index 92f519d..9021614 100644
--- a/src/runcon.c
+++ b/src/runcon.c
@@ -50,12 +50,20 @@
 #include "die.h"
 #include "error.h"
 #include "quote.h"
+#include <sys/prctl.h>

 /* The official name of this program (e.g., no 'g' prefix).  */
 #define PROGRAM_NAME "runcon"

 #define AUTHORS proper_name ("Russell Coker")

+/* For long options that have no equivalent short option, use a
+   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
+enum
+{
+  NO_NEW_PRIVS_ARG = CHAR_MAX + 1,
+};
+
 static struct option const long_options[] =
 {
   {"role", required_argument, NULL, 'r'},
@@ -63,6 +71,7 @@ static struct option const long_options[] =
   {"user", required_argument, NULL, 'u'},
   {"range", required_argument, NULL, 'l'},
   {"compute", no_argument, NULL, 'c'},
+  {"no-new-privs", no_argument, NULL, NO_NEW_PRIVS_ARG},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -76,8 +85,9 @@ usage (int status)
   else
     {
       printf (_("\
-Usage: %s CONTEXT COMMAND [args]\n\
-  or:  %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n\
+Usage: %s [OPTION] CONTEXT COMMAND [args]\n\
+  or:  %s [ --no-new-privs ] [ -c ] [-u USER] [-r ROLE] \
+  [-t TYPE] [-l RANGE] COMMAND [args]\n\
 "), program_name, program_name);
       fputs (_("\
 Run a program in a different SELinux security context.\n\
@@ -93,8 +103,10 @@ With neither CONTEXT nor COMMAND, print the current
security context.\n\
   -u, --user=USER    user identity\n\
   -r, --role=ROLE    role\n\
   -l, --range=RANGE  levelrange\n\
+  --no-new-privs     set NO_NEW_PRIVS bit to forbid additional
privileges\n\
 \n\
 "), stdout);
+
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
       emit_ancillary_info (PROGRAM_NAME);
@@ -114,6 +126,7 @@ main (int argc, char **argv)
   char *file_context = NULL;
   char *new_context = NULL;
   bool compute_trans = false;
+  bool no_new_privs = false;

   context_t con;

@@ -157,7 +170,15 @@ main (int argc, char **argv)
         case 'c':
           compute_trans = true;
           break;
-
+        case NO_NEW_PRIVS_ARG:
+#ifdef PR_SET_NO_NEW_PRIVS
+          no_new_privs = true;
+          break;
+#else
+          die (EXIT_FAILURE, 0,
+               _("--no-new-privs cannot be used in the cureutils version,\
+                 that is currently installed."));
+#endif
         case_GETOPT_HELP_CHAR;
         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
         default:
@@ -253,11 +274,21 @@ main (int argc, char **argv)
   if (setexeccon (context_str (con)) != 0)
     die (EXIT_FAILURE, errno, _("unable to set security context %s"),
          quote (context_str (con)));
+
   if (cur_context != NULL)
     freecon (cur_context);

-  execvp (argv[optind], argv + optind);
+  /* do not allow more privileges than this process has */
+  if (no_new_privs)
+    {
+#ifdef PR_SET_NO_NEW_PRIVS
+      if (prctl (PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) != 0)
+        die (EXIT_FAILURE, errno, _("unable to set NO_NEW_PRIVS bit: %s"),
+             quote (context_str (con)));
+#endif
+    }

+  execvp (argv[optind], argv + optind);
   int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
   error (0, errno, "%s", quote (argv[optind]));
   return exit_status;
diff --git a/tests/local.mk b/tests/local.mk
index e890c9a..0e386ba 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -664,6 +664,7 @@ all_tests =                    \
   tests/rmdir/fail-perm.sh            \
   tests/rmdir/ignore.sh                \
   tests/rmdir/t-slash.sh            \
+    tests/runcon/no-new-privs.sh    \
   tests/tail-2/assert-2.sh            \
   tests/tail-2/big-4gb.sh            \
   tests/tail-2/flush-initial.sh            \
diff --git a/tests/runcon/no-new-privs.sh b/tests/runcon/no-new-privs.sh
new file mode 100755
index 0000000..1186f2e
--- /dev/null
+++ b/tests/runcon/no-new-privs.sh
@@ -0,0 +1,44 @@
+#!/bin/sh
+# Makes sure, inotify will switch to polling mode if directory
+# of the watched file was removed and recreated.
+# (...instead of getting stuck forever)
+
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ runcon
+
+_check_runcon_output ()
+{
+  pattern="$1"
+  file="$2"
+  grep -e "$pattern" "$file" > /dev/null ||
+    { return 1; }
+}
+
+# Run process with inappropriate context
+runcon --no-new-privs -t svirt_lxc_net_t /bin/sh &> out
+
+# Correct behaviour is to permit the operation.
+_check_runcon_output "Operation not permitted" "out" ||\
+# Systems without PR_SET_NO_NEW_PRIVS at the coreutils build time
+# should be sanitized with '...--no-new-privs cannot be used...' message.
+_check_runcon_output "--no-new-privs cannot be used." "out" ||\
+# Sanitize runcon if not run on a SELinux kernel
+_check_runcon_output "runcon may be used only on a SELinux kernel" "out"||\
+fail=1
+
+Exit $fail
-- 
2.9.3


reply via email to

[Prev in Thread] Current Thread [Next in Thread]