selinux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/3] restorecond: migrate to GDbus API provided by glib-gio
@ 2020-04-13 16:24 Nicolas Iooss
  2020-04-13 16:24 ` [PATCH 2/3] restorecond: add systemd user service Nicolas Iooss
  2020-04-13 16:24 ` [PATCH 3/3] restorecond/user: handle SIGTERM properly Nicolas Iooss
  0 siblings, 2 replies; 4+ messages in thread
From: Nicolas Iooss @ 2020-04-13 16:24 UTC (permalink / raw)
  To: selinux

https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=955940 states:

    dbus-glib is a deprecated D-Bus library with some significant design
    flaws, and is essentially unmaintained.

restorecond uses dbus-glib in order to spawn as a D-Bus service on the
session bus of users. This makes restorecond stays so long as the user
session exists.

Migrate from dbus-glib to GDbus API for the implementation of this
feature.

Moreover restorecond currently uses a D-Bus signal to trigger starting
the service. This is quite inappropriate, as stated for example in
https://dbus.freedesktop.org/doc/dbus-tutorial.html#members

    Methods are operations that can be invoked on an object, with
    optional input (aka arguments or "in parameters") and output (aka
    return values or "out parameters"). Signals are broadcasts from the
    object to any interested observers of the object; signals may
    contain a data payload.

Implementing a method is more appropriate. It appears that all D-Bus
users can implement method Ping from interface org.freedesktop.DBus.Peer
(https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-peer)
and that calling this method is enough to trigger the launch of the
service. This can be tested in a shell by running:

    gdbus call --session --dest=org.selinux.Restorecond \
        --object-path=/ --method=org.freedesktop.DBus.Peer.Ping

As this method is automatically provided, there is no need to implement
its handling in the service.

Fixed: https://github.com/SELinuxProject/selinux/issues/217

Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
---
 restorecond/Makefile |   8 +--
 restorecond/user.c   | 140 ++++++++++++++++++++++++-------------------
 2 files changed, 82 insertions(+), 66 deletions(-)

diff --git a/restorecond/Makefile b/restorecond/Makefile
index 12452cd2f8e1..50702c661aeb 100644
--- a/restorecond/Makefile
+++ b/restorecond/Makefile
@@ -13,13 +13,13 @@ autostart_DATA = sealertauto.desktop
 INITDIR ?= /etc/rc.d/init.d
 SELINUXDIR = /etc/selinux
 
-DBUSFLAGS = -DHAVE_DBUS $(shell $(PKG_CONFIG) --cflags dbus-glib-1)
-DBUSLIB = $(shell $(PKG_CONFIG) --libs dbus-glib-1)
+GIO_CFLAGS = -DHAVE_DBUS $(shell $(PKG_CONFIG) --cflags gio-2.0)
+GIO_LIBS = $(shell $(PKG_CONFIG) --libs gio-2.0)
 
 CFLAGS ?= -g -Werror -Wall -W
-override CFLAGS += $(DBUSFLAGS)
+override CFLAGS += $(GIO_CFLAGS)
 
-override LDLIBS += -lselinux $(DBUSLIB)
+override LDLIBS += -lselinux $(GIO_LIBS)
 
 all: restorecond
 
diff --git a/restorecond/user.c b/restorecond/user.c
index 8f9323077a26..f940fd4e6678 100644
--- a/restorecond/user.c
+++ b/restorecond/user.c
@@ -2,6 +2,7 @@
  * restorecond
  *
  * Copyright (C) 2006-2009 Red Hat
+ * Copyright (C) 2020 Nicolas Iooss
  * see file 'COPYING' for use and warranty information
  *
  * This program is free software; you can redistribute it and/or
@@ -21,7 +22,7 @@
  *
  * Authors:
  *   Dan Walsh <dwalsh@redhat.com>
- *
+ *   Nicolas Iooss <nicolas.iooss@m4x.org>
 */
 
 #define _GNU_SOURCE
@@ -33,73 +34,75 @@
 #include <string.h>
 #include <unistd.h>
 #include <ctype.h>
+#include <sys/file.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <syslog.h>
 #include <limits.h>
 #include <fcntl.h>
 
+#include <selinux/selinux.h>
+
 #include "restorecond.h"
 #include "stringslist.h"
 #include <glib.h>
-#ifdef HAVE_DBUS
-#include <dbus/dbus.h>
-#include <dbus/dbus-glib.h>
-#include <dbus/dbus-glib-lowlevel.h>
 
-static DBusHandlerResult signal_filter (DBusConnection *connection, DBusMessage *message, void *user_data);
+static int local_lock_fd = -1;
 
-static const char *PATH="/org/selinux/Restorecond";
-//static const char *BUSNAME="org.selinux.Restorecond";
-static const char *INTERFACE="org.selinux.RestorecondIface";
-static const char *RULE="type='signal',interface='org.selinux.RestorecondIface'";
+#ifdef HAVE_DBUS
+#include <gio/gio.h>
 
-static int local_lock_fd = -1;
+static const char *DBUS_NAME = "org.selinux.Restorecond";
 
-static DBusHandlerResult
-signal_filter (DBusConnection *connection  __attribute__ ((__unused__)), DBusMessage *message, void *user_data)
+static void on_name_acquired(GDBusConnection *connection G_GNUC_UNUSED,
+			     const gchar *name,
+			     gpointer user_data G_GNUC_UNUSED)
 {
-  /* User data is the event loop we are running in */
-  GMainLoop *loop = user_data;
+	if (debug_mode)
+		g_print("D-Bus name acquired: %s\n", name);
+}
 
-  /* A signal from the bus saying we are about to be disconnected */
-  if (dbus_message_is_signal
-        (message, INTERFACE, "Stop")) {
+static void on_name_lost(GDBusConnection *connection G_GNUC_UNUSED,
+			 const gchar *name,
+			 gpointer user_data)
+{
+	/* Exit when the D-Bus connection closes */
+	GMainLoop *loop = user_data;
 
-      /* Tell the main loop to quit */
-      g_main_loop_quit (loop);
-      /* We have handled this message, don't pass it on */
-      return DBUS_HANDLER_RESULT_HANDLED;
-  }
-  /* A Ping signal on the com.burtonini.dbus.Signal interface */
-  else if (dbus_message_is_signal (message, INTERFACE, "Start")) {
-    DBusError error;
-    dbus_error_init (&error);
-    g_print("Start received\n");
-    return DBUS_HANDLER_RESULT_HANDLED;
-  }
-  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	if (debug_mode)
+		g_print("D-Bus name lost (%s), exiting\n", name);
+	g_main_loop_quit(loop);
 }
 
-static int dbus_server(GMainLoop *loop) {
-    DBusConnection *bus;
-    DBusError error;
-    dbus_error_init (&error);
-    bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
-    if (bus) {
-	dbus_connection_setup_with_g_main (bus, NULL);
-
-	/* listening to messages from all objects as no path is specified */
-	dbus_bus_add_match (bus, RULE, &error); // see signals from the given interfacey
-	dbus_connection_add_filter (bus, signal_filter, loop, NULL);
+/**
+ * Try starting a D-Bus server on the session bus.
+ * Returns -1 if the connection failed, so that a local server can be launched
+ */
+static int dbus_server(GMainLoop *loop)
+{
+	GDBusConnection *bus;
+	guint client_id;
+
+	bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL);
+	if (!bus)
+		return -1;
+
+	client_id = g_bus_own_name_on_connection(
+		bus,
+		DBUS_NAME,
+		G_BUS_NAME_OWNER_FLAGS_NONE,
+		on_name_acquired,
+		on_name_lost,
+		loop,
+		NULL);
+	g_object_unref(bus);
+	if (client_id == 0)
+		return -1;
+
 	return 0;
-    }
-    return -1;
 }
 
 #endif
-#include <selinux/selinux.h>
-#include <sys/file.h>
 
 /* size of the event structure, not counting name */
 #define EVENT_SIZE  (sizeof (struct inotify_event))
@@ -167,29 +170,42 @@ io_channel_callback
 
 int start() {
 #ifdef HAVE_DBUS
-	DBusConnection *bus;
-	DBusError error;
-	DBusMessage *message;
+	GDBusConnection *bus;
+	GError *err = NULL;
+	GVariant *result;
 
 	/* Get a connection to the session bus */
-	dbus_error_init (&error);
-	bus = dbus_bus_get (DBUS_BUS_SESSION, &error);
+	bus = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &err);
 	if (!bus) {
 		if (debug_mode)
-			g_warning ("Failed to connect to the D-BUS daemon: %s", error.message);
-		dbus_error_free (&error);
+			g_warning("Failed to connect to the D-BUS daemon: %s", err->message);
+		g_error_free(err);
 		return 1;
 	}
 
-
-	/* Create a new signal "Start" on the interface,
-	 * from the object  */
-	message = dbus_message_new_signal (PATH,
-					   INTERFACE, "Start");
-	/* Send the signal */
-	dbus_connection_send (bus, message, NULL);
-	/* Free the signal now we have finished with it */
-	dbus_message_unref (message);
+	/* Start restorecond D-Bus service by pinging its bus name
+	 *
+	 * https://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-peer
+	 */
+	result = g_dbus_connection_call_sync(bus,
+					     DBUS_NAME, /* bus name */
+					     "/", /* object path */
+					     "org.freedesktop.DBus.Peer", /* interface */
+					     "Ping", /* method */
+					     NULL, /* parameters */
+					     NULL, /* reply_type */
+					     G_DBUS_CALL_FLAGS_NONE,
+					     -1, /* timeout_msec */
+					     NULL,
+					     &err);
+	if (!result) {
+		g_object_unref(bus);
+		if (debug_mode)
+			g_warning("Failed to start %s: %s", DBUS_NAME, err->message);
+		g_error_free(err);
+		return 1;
+	}
+	g_object_unref(bus);
 #endif /* HAVE_DBUS */
 	return 0;
 }
-- 
2.26.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/3] restorecond: add systemd user service
  2020-04-13 16:24 [PATCH 1/3] restorecond: migrate to GDbus API provided by glib-gio Nicolas Iooss
@ 2020-04-13 16:24 ` Nicolas Iooss
  2020-04-13 16:24 ` [PATCH 3/3] restorecond/user: handle SIGTERM properly Nicolas Iooss
  1 sibling, 0 replies; 4+ messages in thread
From: Nicolas Iooss @ 2020-04-13 16:24 UTC (permalink / raw)
  To: selinux

When running restorecond in user sessions using D-Bus activation,
restorecond's process is spawned in the CGroup of the D-Bus daemon:

    $ systemctl --user status
    [...]
       CGroup: /user.slice/user-1000.slice/user@1000.service
               ├─init.scope
               │ ├─1206 /usr/lib/systemd/systemd --user
               │ └─1208 (sd-pam)
               └─dbus.service
                 ├─1628 /usr/bin/dbus-daemon --session --address=systemd:
                 └─4570 /usr/sbin/restorecond -u

In order to separate it, introduce a systemd unit for
restorecond-started-as-user.

After this patch:

       CGroup: /user.slice/user-1000.slice/user@1000.service
               ├─restorecond-user.service
               │ └─2871 /usr/sbin/restorecond -u
               ├─init.scope
               │ ├─481 /usr/lib/systemd/systemd --user
               │ └─485 (sd-pam)
               └─dbus.service
                 └─2868 /usr/bin/dbus-daemon --session --address=systemd:

Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
---
 restorecond/Makefile                        |  2 ++
 restorecond/org.selinux.Restorecond.service |  1 +
 restorecond/restorecond-user.service        | 10 ++++++++++
 3 files changed, 13 insertions(+)
 create mode 100644 restorecond/restorecond-user.service

diff --git a/restorecond/Makefile b/restorecond/Makefile
index 50702c661aeb..501f89dfca57 100644
--- a/restorecond/Makefile
+++ b/restorecond/Makefile
@@ -50,6 +50,8 @@ install: all
 	install -m 644 org.selinux.Restorecond.service  $(DESTDIR)$(DBUSSERVICEDIR)/org.selinux.Restorecond.service
 	-mkdir -p $(DESTDIR)$(SYSTEMDDIR)/system
 	install -m 644 restorecond.service $(DESTDIR)$(SYSTEMDDIR)/system/
+	-mkdir -p $(DESTDIR)$(SYSTEMDDIR)/user
+	install -m 644 restorecond-user.service $(DESTDIR)$(SYSTEMDDIR)/user/
 relabel: install
 	/sbin/restorecon $(DESTDIR)$(SBINDIR)/restorecond 
 
diff --git a/restorecond/org.selinux.Restorecond.service b/restorecond/org.selinux.Restorecond.service
index 0ef5f0b5cdc5..55989a9cbbd0 100644
--- a/restorecond/org.selinux.Restorecond.service
+++ b/restorecond/org.selinux.Restorecond.service
@@ -1,3 +1,4 @@
 [D-BUS Service]
 Name=org.selinux.Restorecond
 Exec=/usr/sbin/restorecond -u
+SystemdService=restorecond-user.service
diff --git a/restorecond/restorecond-user.service b/restorecond/restorecond-user.service
new file mode 100644
index 000000000000..28ca770f94cb
--- /dev/null
+++ b/restorecond/restorecond-user.service
@@ -0,0 +1,10 @@
+[Unit]
+Description=Restorecon maintaining path file context (user service)
+Documentation=man:restorecond(8)
+ConditionPathExists=/etc/selinux/restorecond_user.conf
+ConditionSecurity=selinux
+
+[Service]
+Type=dbus
+BusName=org.selinux.Restorecond
+ExecStart=/usr/sbin/restorecond -u
-- 
2.26.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 3/3] restorecond/user: handle SIGTERM properly
  2020-04-13 16:24 [PATCH 1/3] restorecond: migrate to GDbus API provided by glib-gio Nicolas Iooss
  2020-04-13 16:24 ` [PATCH 2/3] restorecond: add systemd user service Nicolas Iooss
@ 2020-04-13 16:24 ` Nicolas Iooss
  2020-04-27 20:58   ` Petr Lautrbach
  1 sibling, 1 reply; 4+ messages in thread
From: Nicolas Iooss @ 2020-04-13 16:24 UTC (permalink / raw)
  To: selinux

When restorecond starts, it installs a SIGTERM handler in order to exit
cleanly (by removing its PID file). When restorecond --user starts,
there is no PID file, and g_main_loop_run() does not stop when master_fd
is closed. This leads to an unkillable service, which is an issue.

Fix this by overriding the handler for SIGTERM in restorecond --user.

Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
---
 restorecond/user.c | 54 +++++++++++++++++++++++++++++++---------------
 1 file changed, 37 insertions(+), 17 deletions(-)

diff --git a/restorecond/user.c b/restorecond/user.c
index f940fd4e6678..a24b8407b048 100644
--- a/restorecond/user.c
+++ b/restorecond/user.c
@@ -46,6 +46,7 @@
 #include "restorecond.h"
 #include "stringslist.h"
 #include <glib.h>
+#include <glib-unix.h>
 
 static int local_lock_fd = -1;
 
@@ -250,35 +251,54 @@ static void end_local_server(void) {
 	local_lock_fd = -1;
 }
 
+static int sigterm_handler(gpointer user_data)
+{
+	GMainLoop *loop = user_data;
+
+	if (debug_mode)
+		g_print("Received SIGTERM, exiting\n");
+	g_main_loop_quit(loop);
+	return FALSE;
+}
+
+
 int server(int master_fd, const char *watch_file) {
-    GMainLoop *loop;
+	GMainLoop *loop;
 
-    loop = g_main_loop_new (NULL, FALSE);
+	loop = g_main_loop_new (NULL, FALSE);
 
 #ifdef HAVE_DBUS
-    if (dbus_server(loop) != 0)
+	if (dbus_server(loop) != 0)
 #endif /* HAVE_DBUS */
-	    if (local_server())
-		    goto end;
+		if (local_server())
+			goto end;
 
-    read_config(master_fd, watch_file);
+	read_config(master_fd, watch_file);
 
-    if (watch_list_isempty()) goto end;
+	if (watch_list_isempty())
+		goto end;
 
-    set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
+	set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
 
-    GIOChannel *c = g_io_channel_unix_new(master_fd);
+	GIOChannel *c = g_io_channel_unix_new(master_fd);
 
-    g_io_add_watch_full( c,
-			 G_PRIORITY_HIGH,
-			 G_IO_IN|G_IO_ERR|G_IO_HUP,
-			 io_channel_callback, NULL, NULL);
+	g_io_add_watch_full(c,
+			    G_PRIORITY_HIGH,
+			    G_IO_IN|G_IO_ERR|G_IO_HUP,
+			    io_channel_callback, NULL, NULL);
 
-    g_main_loop_run (loop);
+	/* Handle SIGTERM */
+	g_unix_signal_add_full(G_PRIORITY_DEFAULT,
+			       SIGTERM,
+			       sigterm_handler,
+			       loop,
+			       NULL);
+
+	g_main_loop_run (loop);
 
 end:
-    end_local_server();
-    g_main_loop_unref (loop);
-    return 0;
+	end_local_server();
+	g_main_loop_unref (loop);
+	return 0;
 }
 
-- 
2.26.0


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 3/3] restorecond/user: handle SIGTERM properly
  2020-04-13 16:24 ` [PATCH 3/3] restorecond/user: handle SIGTERM properly Nicolas Iooss
@ 2020-04-27 20:58   ` Petr Lautrbach
  0 siblings, 0 replies; 4+ messages in thread
From: Petr Lautrbach @ 2020-04-27 20:58 UTC (permalink / raw)
  To: Nicolas Iooss; +Cc: selinux

[-- Attachment #1: Type: text/plain, Size: 3046 bytes --]

On Mon, Apr 13, 2020 at 06:24:13PM +0200, Nicolas Iooss wrote:
> When restorecond starts, it installs a SIGTERM handler in order to exit
> cleanly (by removing its PID file). When restorecond --user starts,
> there is no PID file, and g_main_loop_run() does not stop when master_fd
> is closed. This leads to an unkillable service, which is an issue.
> 
> Fix this by overriding the handler for SIGTERM in restorecond --user.
> 
> Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>

The whole patchset

Acked-by: Petr Lautrbach <plautrba@redhat.com>

and merged.

Thanks!


> ---
>  restorecond/user.c | 54 +++++++++++++++++++++++++++++++---------------
>  1 file changed, 37 insertions(+), 17 deletions(-)
> 
> diff --git a/restorecond/user.c b/restorecond/user.c
> index f940fd4e6678..a24b8407b048 100644
> --- a/restorecond/user.c
> +++ b/restorecond/user.c
> @@ -46,6 +46,7 @@
>  #include "restorecond.h"
>  #include "stringslist.h"
>  #include <glib.h>
> +#include <glib-unix.h>
>  
>  static int local_lock_fd = -1;
>  
> @@ -250,35 +251,54 @@ static void end_local_server(void) {
>  	local_lock_fd = -1;
>  }
>  
> +static int sigterm_handler(gpointer user_data)
> +{
> +	GMainLoop *loop = user_data;
> +
> +	if (debug_mode)
> +		g_print("Received SIGTERM, exiting\n");
> +	g_main_loop_quit(loop);
> +	return FALSE;
> +}
> +
> +
>  int server(int master_fd, const char *watch_file) {
> -    GMainLoop *loop;
> +	GMainLoop *loop;
>  
> -    loop = g_main_loop_new (NULL, FALSE);
> +	loop = g_main_loop_new (NULL, FALSE);
>  
>  #ifdef HAVE_DBUS
> -    if (dbus_server(loop) != 0)
> +	if (dbus_server(loop) != 0)
>  #endif /* HAVE_DBUS */
> -	    if (local_server())
> -		    goto end;
> +		if (local_server())
> +			goto end;
>  
> -    read_config(master_fd, watch_file);
> +	read_config(master_fd, watch_file);
>  
> -    if (watch_list_isempty()) goto end;
> +	if (watch_list_isempty())
> +		goto end;
>  
> -    set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
> +	set_matchpathcon_flags(MATCHPATHCON_NOTRANS);
>  
> -    GIOChannel *c = g_io_channel_unix_new(master_fd);
> +	GIOChannel *c = g_io_channel_unix_new(master_fd);
>  
> -    g_io_add_watch_full( c,
> -			 G_PRIORITY_HIGH,
> -			 G_IO_IN|G_IO_ERR|G_IO_HUP,
> -			 io_channel_callback, NULL, NULL);
> +	g_io_add_watch_full(c,
> +			    G_PRIORITY_HIGH,
> +			    G_IO_IN|G_IO_ERR|G_IO_HUP,
> +			    io_channel_callback, NULL, NULL);
>  
> -    g_main_loop_run (loop);
> +	/* Handle SIGTERM */
> +	g_unix_signal_add_full(G_PRIORITY_DEFAULT,
> +			       SIGTERM,
> +			       sigterm_handler,
> +			       loop,
> +			       NULL);
> +
> +	g_main_loop_run (loop);
>  
>  end:
> -    end_local_server();
> -    g_main_loop_unref (loop);
> -    return 0;
> +	end_local_server();
> +	g_main_loop_unref (loop);
> +	return 0;
>  }
>  
> -- 
> 2.26.0
> 

-- 
()  ascii ribbon campaign - against html e-mail 
/\  www.asciiribbon.org   - against proprietary attachments

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-04-27 20:58 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-04-13 16:24 [PATCH 1/3] restorecond: migrate to GDbus API provided by glib-gio Nicolas Iooss
2020-04-13 16:24 ` [PATCH 2/3] restorecond: add systemd user service Nicolas Iooss
2020-04-13 16:24 ` [PATCH 3/3] restorecond/user: handle SIGTERM properly Nicolas Iooss
2020-04-27 20:58   ` Petr Lautrbach

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).