[Utopia] Re: Required privileges of hald



Hi David!

On 2004-08-02 12:01 +0200, David Zeuthen wrote:
> However, if you guys are going to patch hal anyway it would of course be
> easier to include the changes upstream if. And, in the long term, if
> we're going to run as a unprivileged user we just might start putting it
> in. I'm not sure though, there's also the SELinux stuff to consider.

I agree. Especially since the privilege dropping is (currently)
optional, i. e. even if you adopt all patches, there will still be no
incompatible behaviour unless you explicitly start hal with
--drop-privileges.

I attached four patches which I propose for upstream inclusion. These
are based against version 20040711. Let me know if something needs to
be adapted to more recent versions.

- 01_log_to_syslog actually uses syslog to log instead of logging to
  stderr. Since stderr is closed and redirected to /dev/null, hal logs
  into the void.

- 02_ioctl_errors adds error log messages for all ioctls which were
  not checked before. Good for debugging.

- 03_min_privileges adds the option --drop-privileges to hald which
  keeps only necessary capabilities and lets hald run as unprivileged
  user HAL_USER

- 04_fix_hal_conf_in change the hardcoded "root" user to @HAL_USER@ in
  hal.conf.in.

01, 02 and 04 have nothing to do with security and just fix
bugs/enhance functionality. As I already explained, 03 should not
break anything, too as long as --drop-privileges is not used.

Thanks for considering and have a nice day!

Martin

-- 
Martin Pitt                 Debian GNU/Linux Developer
martin piware de                      mpitt debian org
http://www.piware.de             http://www.debian.org
--- hal-0.2.93+20040711.orig/hald/logger.c
+++ hal-0.2.93+20040711/hald/logger.c
@@ -31,6 +31,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdarg.h>
+#include <syslog.h>
 
 #include "logger.h"
 
@@ -53,6 +54,8 @@
 void
 logger_init ()
 {
+    openlog( "hald", 0, LOG_DAEMON );
+
 }
 
 /** Setup logging entry
@@ -83,6 +86,7 @@
 	va_list args;
 	char buf[512];
 	char *pri;
+	int syslog_prio;
 
 	va_start (args, format);
 	vsnprintf (buf, 512, format, args);
@@ -90,25 +94,30 @@
 	switch (priority) {
 	case HAL_LOGPRI_TRACE:
 		pri = "[T]";
+		syslog_prio = LOG_DEBUG;
 		break;
 	case HAL_LOGPRI_DEBUG:
 		pri = "[D]";
+		syslog_prio = LOG_DEBUG;
 		break;
 	case HAL_LOGPRI_INFO:
 		pri = "[I]";
+		syslog_prio = LOG_INFO;
 		break;
 	case HAL_LOGPRI_WARNING:
 		pri = "[W]";
+		syslog_prio = LOG_WARNING;
 		break;
 	default:		/* explicit fallthrough */
 	case HAL_LOGPRI_ERROR:
 		pri = "[E]";
+		syslog_prio = LOG_ERR;
 		break;
 	}
 
 	/** @todo Make programmatic interface to logging */
 	if (priority != HAL_LOGPRI_TRACE)
-		fprintf (stderr, "%s %s:%d %s() : %s\n",
+		syslog (syslog_prio, "%s %s:%d %s() : %s\n",
 			 pri, file, line, function, buf);
 
 	va_end (args);
--- hal-0.2.93+20040711.orig/hald/linux/input_class_device.c
+++ hal-0.2.93+20040711/hald/linux/input_class_device.c
@@ -38,6 +38,7 @@
 #include <limits.h>
 #include <fcntl.h>
 #include <linux/input.h>
+#include <errno.h>
 
 #include "../logger.h"
 #include "../device_store.h"
@@ -135,7 +136,8 @@
                 if (ioctl(fd, EVIOCGNAME(sizeof name), name) >= 0) {
                         hal_device_property_set_string (d, "info.product",
                                                         name);
-                }
+                } else
+		    HAL_ERROR(("EVIOCGNAME failed: %s\n", strerror(errno)));
         }
 
         /* @todo add more ioctl()'s here */

--- hal-0.2.93+20040711.orig/hald/linux/printer_class_device.c
+++ hal-0.2.93+20040711/hald/linux/printer_class_device.c
@@ -41,6 +41,7 @@
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <fcntl.h>
+#include <errno.h>
 
 #include "../logger.h"
 #include "../device_store.h"
@@ -115,7 +116,9 @@
 		   device_id) < 0) {
 		close (fd);
 		return;
-	}
+	} else
+	    HAL_ERROR(("LPIOC_GET_DEVICE_ID failed: %s\n", strerror(errno)));
+
 
 	close (fd);
 
--- hal-0.2.93+20040711.orig/hald/linux/block_class_device.c
+++ hal-0.2.93+20040711/hald/linux/block_class_device.c
@@ -187,7 +187,8 @@
 	if (fd < 0)
 		return;
 		
-	ioctl (fd, CDROM_SET_OPTIONS, CDO_USE_FFLAGS);
+	if( ioctl (fd, CDROM_SET_OPTIONS, CDO_USE_FFLAGS) < 0 )
+	    HAL_ERROR(("CDROM_SET_OPTIONS failed: %s\n", strerror(errno)));
 		
 	capabilities = ioctl (fd, CDROM_GET_CAPABILITY, 0);
 	if (capabilities < 0) {
@@ -674,6 +675,10 @@
 			got_disc = TRUE;
 			break;
 
+		case -1:
+		    HAL_ERROR(("CDROM_DRIVE_STATUS failed: %s\n", strerror(errno)));
+		    break;
+
 		default:
 			break;
 		}
@@ -827,6 +832,10 @@
 					child, "volume.disc.is_blank", TRUE);
 				break;
 
+			case -1:
+			    HAL_ERROR(("CDROM_DISC_STATUS failed: %s\n", strerror(errno)));
+			    break;
+
 			default:		/* should never see this */
 				hal_device_property_set_string (child,
 						"volume.disc_type",
--- hal-0.2.93+20040711.orig/hald/hald.c
+++ hal-0.2.93+20040711/hald/hald.c
@@ -38,6 +38,9 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <signal.h>
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#include <grp.h>
 
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib.h>
@@ -161,6 +164,8 @@
 	fprintf (stderr,
 		 "\n"
 		 "        --daemon=yes|no    Become a daemon\n"
+		 "        --drop-privileges  Run as normal user instead of root (calling of external\n"
+		 "                           scripts to modify fstab etc. will not work any more)\n"
 		 "        --help             Show this information and exit\n"
 		 "\n"
 		 "The HAL daemon detects devices present in the system and provides the\n"
@@ -175,6 +180,70 @@
 /** If #TRUE, we will daemonize */
 static dbus_bool_t opt_become_daemon = TRUE;
 
+
+/** 
+ * Drop all but necessary privileges from hald when it runs as root.  Set the
+ * running user id to 'hal' and groups to 'disk', 'floppy', and 'cdrom'. Drops
+ * all unnecessary capabilities. On error, a message is sent to syslog and
+ * the program terminates with exit code -1.
+ */
+void
+drop_privileges()
+{
+    cap_t cap;
+    struct passwd *pw = NULL;
+    struct group *gr = NULL;
+
+    /* determine user id */
+    pw = getpwnam( HAL_USER );
+    if( !pw )  {
+	HAL_ERROR(( "drop_privileges: user " HAL_USER " does not exist\n" ));
+	exit( -1 );
+    }
+
+    /* determine primary group id */
+    gr = getgrnam( HAL_GROUP );
+    if( !gr ) {
+	HAL_ERROR(( "drop_privileges: group " HAL_GROUP " does not exist\n" ));
+	exit( -1 );
+    }
+
+    /* keep capabilities and change uid/gid */
+    if( prctl( PR_SET_KEEPCAPS, 1, 0, 0, 0 ) ) {
+	HAL_ERROR(( "drop_privileges: could not keep capabilities\n" ));
+	exit( -1 );
+    }
+
+    if( initgroups( HAL_USER, gr->gr_gid ) ) {
+	HAL_ERROR(( "drop_privileges: could not initialize groups\n" ));
+	exit( -1 );
+    }
+
+    if( setgid( gr->gr_gid ) ) {
+	HAL_ERROR(( "drop_privileges: could not set group id\n" ));
+	exit( -1 );
+    }
+
+    if( setuid( pw->pw_uid ) ) {
+	HAL_ERROR(( "drop_privileges: could not set user id\n" ));
+	exit( -1 );
+    }
+
+    /* only keep necessary capabilities */
+    cap = cap_from_text( "cap_net_admin=ep" );
+
+    if( cap_set_proc( cap ) ) {
+	HAL_ERROR(( "drop_privileges: could not install capabilities\n" ));
+	exit( -1 );
+    }
+
+    if( cap_free( cap ) ) {
+	HAL_ERROR(( "drop_privileges: cap_free\n" ));
+	exit( -1 );
+    }
+}
+
+
 /** Entry point for HAL daemon
  *
  *  @param  argc                Number of arguments
@@ -194,6 +263,7 @@
 		static struct option long_options[] = {
 			{"daemon", 1, NULL, 0},
 			{"help", 0, NULL, 0},
+			{"drop-privileges", 0, NULL, 0},
 			{NULL, 0, NULL, 0}
 		};
 
@@ -218,7 +288,8 @@
 					usage ();
 					return 1;
 				}
-			}
+			} else if (strcmp(opt, "drop-privileges") == 0)
+			    drop_privileges ();
 			break;
 
 		default:
--- hal-0.2.93+20040711.orig/hald/Makefile.am
+++ hal-0.2.93+20040711/hald/Makefile.am
@@ -71,7 +71,7 @@
 hald_SOURCES +=                                                         \
 	linux/volume_id/volume_id.h	linux/volume_id/volume_id.c
 
-hald_LDADD = @PACKAGE_LIBS@
+hald_LDADD = @PACKAGE_LIBS@ -lcap
 
 #### Init scripts fun
 SCRIPT_IN_FILES=haldaemon.in
--- hal-0.2.93+20040711.orig/hal.conf.in
+++ hal-0.2.93+20040711/hal.conf.in
@@ -9,7 +9,7 @@
 
   <!-- Only user @HAL_USER@ can own the HAL service and be an agent -->
   <!-- policy user="@HAL_USER@" We require root to sniff mii registers -->
-  <policy user="root">
+  <policy user="@HAL_USER@">
     <allow own="org.freedesktop.Hal"/>
 
     <allow send_interface="org.freedesktop.Hal.AgentManager"
@@ -19,7 +19,7 @@
   </policy>
 
   <!-- Only root can use the Linux.Hotplug interface -->
-  <policy user="root">
+  <policy user="@HAL_USER@">
     <allow send_interface="org.freedesktop.Hal.Linux.Hotplug"
            send_destination="org.freedesktop.Hal"/>
     <allow receive_interface="org.freedesktop.Hal.Linux.Hotplug"
@@ -28,7 +28,7 @@
 
   <!-- Any user in the @HAL_GROUP@ group can use the AgentManager interface -->
   <!-- policy group="@HAL_GROUP@" Doesn't work on dbus 0.20. Works in CVS -->
-  <policy user="root">
+  <policy user="@HAL_USER@">
     <allow send_interface="org.freedesktop.Hal.AgentManager"
            send_destination="org.freedesktop.Hal"/>
     <allow receive_interface="org.freedesktop.Hal.AgentManager"

Attachment: pgppKfIjtXnMd.pgp
Description: PGP signature



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