From 0329e09b6934bd1d707f48271353fc4a9527542d Mon Sep 17 00:00:00 2001 From: Matthew Leeds Date: Wed, 24 Jul 2019 14:45:16 -0700 Subject: [PATCH] service: Allow services to be run as root This commit adds a GssService:allow-root property to allow subclasses to let themselves be run as root. The specific situation this is meant for is a service running as root to avoid being killed when systemd gains control after the pivot to the final root filesystem (all non-root processes are killed at that point).[1] [1] https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/ --- libgsystemservice/service.c | 43 +++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/libgsystemservice/service.c b/libgsystemservice/service.c index 28e8ab1..84e7a9d 100644 --- a/libgsystemservice/service.c +++ b/libgsystemservice/service.c @@ -91,6 +91,7 @@ typedef struct GError *run_error; /* (nullable) (owned) */ gboolean run_exited; int run_exit_signal; + gboolean allow_root; GMainContext *context; /* (owned) */ @@ -110,6 +111,7 @@ typedef enum PROP_BUS_TYPE, PROP_SERVICE_ID, PROP_INACTIVITY_TIMEOUT, + PROP_ALLOW_ROOT, } GssServiceProperty; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GssService, gss_service, G_TYPE_OBJECT) @@ -118,7 +120,7 @@ static void gss_service_class_init (GssServiceClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; - GParamSpec *props[PROP_INACTIVITY_TIMEOUT + 1] = { NULL, }; + GParamSpec *props[PROP_ALLOW_ROOT + 1] = { NULL, }; object_class->dispose = gss_service_dispose; object_class->get_property = gss_service_get_property; @@ -231,6 +233,23 @@ gss_service_class_init (GssServiceClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + /** + * GssService:allow-root: + * + * If %TRUE, the service can be run by root. Otherwise, and by default, + * gss_service_run() will fail if the UID or effective UID is zero. + * + * Since: 0.1.0 + */ + props[PROP_ALLOW_ROOT] = + g_param_spec_boolean ("allow-root", "Allow Root", + "Whether the service should be allowed to run " + "as root (UID 0).", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, G_N_ELEMENTS (props), props); } @@ -309,6 +328,9 @@ gss_service_get_property (GObject *object, case PROP_INACTIVITY_TIMEOUT: g_value_set_uint (value, priv->inactivity_timeout_ms); break; + case PROP_ALLOW_ROOT: + g_value_set_boolean (value, priv->allow_root); + break; default: g_assert_not_reached (); } @@ -352,6 +374,10 @@ gss_service_set_property (GObject *object, case PROP_INACTIVITY_TIMEOUT: gss_service_set_inactivity_timeout (self, g_value_get_uint (value)); break; + case PROP_ALLOW_ROOT: + /* Construct only. */ + priv->allow_root = g_value_get_boolean (value); + break; default: g_assert_not_reached (); } @@ -560,13 +586,16 @@ gss_service_run (GssService *self, bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); - /* Ensure we are not running as root — we don’t need those privileges. */ - if (getuid () == 0 || geteuid () == 0) + if (!priv->allow_root) { - g_set_error_literal (error, GSS_SERVICE_ERROR, - GSS_SERVICE_ERROR_INVALID_ENVIRONMENT, - _("This daemon must not be run as root.")); - return; + /* Ensure we are not running as root — we don’t need those privileges. */ + if (getuid () == 0 || geteuid () == 0) + { + g_set_error_literal (error, GSS_SERVICE_ERROR, + GSS_SERVICE_ERROR_INVALID_ENVIRONMENT, + _("This daemon must not be run as root.")); + return; + } } gss_service_hold (self); -- GitLab