Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 Feb 2013 04:30:01 GMT
From:      Danny Warren <danny@dannywarren.com>
To:        gnome@FreeBSD.org
Subject:   Re: ports/176203: [patch] devel/gamin: Drop privileges to effective user and group
Message-ID:  <201302170430.r1H4U1d0094279@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR ports/176203; it has been noted by GNATS.

From: Danny Warren <danny@dannywarren.com>
To: bug-followup@FreeBSD.org, danny@dannywarren.com
Cc:  
Subject: Re: ports/176203: [patch] devel/gamin: Drop privileges to effective
 user and group
Date: Sat, 16 Feb 2013 20:17:55 -0800

 This is a multi-part message in MIME format.
 --------------090305060503020705000402
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 Apologies, I forgot to include one of the files in the patch (and 
 instead included one of them twice).
 
 Here is an updated patch.
 
 --------------090305060503020705000402
 Content-Type: text/plain; charset=windows-1252;
  name="gamin-drop_privileges.patch.txt"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="gamin-drop_privileges.patch.txt"
 
 --- Makefile.orig	2013-02-16 19:09:52.507178348 -0800
 +++ Makefile	2013-02-16 16:18:30.230098850 -0800
 @@ -27,9 +27,10 @@
  GNU_CONFIGURE=	yes
  
  .if !defined(GAMIN_SLAVE)
 -OPTIONS_DEFINE=	GAM_POLLER LIBINOTIFY 
 +OPTIONS_DEFINE=	GAM_POLLER LIBINOTIFY RUN_AS_EUID
  GAM_POLLER_DESC=Use gamin's poller instead of kqueue's
  LIBINOTIFY_DESC=Use libinotify as the FAM backend
 +RUN_AS_EUID_DESC=Drop privileges to effective user
  .endif
  
  .include <bsd.port.options.mk>
 @@ -48,6 +49,10 @@
  .endif
  .endif
  
 +.if ${PORT_OPTIONS:MRUN_AS_EUID}
 +CPPFLAGS+=	-DRUN_AS_EUID=1
 +.endif
 +
  post-patch:
  	@${REINPLACE_CMD} "s|/etc|${PREFIX}/etc|g" ${WRKSRC}/server/gam_conf.c
  
 --- libgamin/gam_api.c.orig	2007-08-27 03:21:03.000000000 -0700
 +++ libgamin/gam_api.c	2013-02-16 15:51:11.927100135 -0800
 @@ -14,6 +14,7 @@
  #include <sys/socket.h>
  #include <sys/un.h>
  #include <sys/uio.h>
 +#include <string.h>
  #include "fam.h"
  #include "gam_protocol.h"
  #include "gam_data.h"
 @@ -117,7 +118,11 @@
      if (user_name[0] != 0)
          return (user_name);
  
 +#ifdef RUN_AS_EUID
 +    pw = getpwuid(geteuid());
 +#else
      pw = getpwuid(getuid());
 +#endif
  
      if (pw != NULL) {
  	strncpy(user_name, pw->pw_name, 99);
 @@ -224,7 +229,11 @@
  	free(dir);
  	return(0);
      }
 +#ifdef RUN_AS_EUID
 +    if (st.st_uid != geteuid()) {
 +#else
      if (st.st_uid != getuid()) {
 +#endif
  	gam_error(DEBUG_INFO,
  		  "Socket directory %s has different owner\n",
  		  dir);
 @@ -301,7 +310,11 @@
      if (ret < 0)
  	return(0);
      
 +#ifdef RUN_AS_EUID
 +    if (st.st_uid != geteuid()) {
 +#else
      if (st.st_uid != getuid()) {
 +#endif
  	gam_error(DEBUG_INFO,
  		  "Socket %s has different owner\n",
  		  path);
 @@ -428,10 +441,10 @@
  {
      char data[2] = { 0, 0 };
      int written;
 -#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
 -    struct {
 +#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
 +    union {
  	    struct cmsghdr hdr;
 -	    struct cmsgcred cred;
 +	    char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
      } cmsg;
      struct iovec iov;
      struct msghdr msg;
 @@ -443,16 +456,16 @@
      msg.msg_iov = &iov;
      msg.msg_iovlen = 1;
  
 -    msg.msg_control = &cmsg;
 -    msg.msg_controllen = sizeof (cmsg);
 +    msg.msg_control = (caddr_t) &cmsg;
 +    msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
      memset (&cmsg, 0, sizeof (cmsg));
 -    cmsg.hdr.cmsg_len = sizeof (cmsg);
 +    cmsg.hdr.cmsg_len = CMSG_LEN (sizeof (struct cmsgcred));
      cmsg.hdr.cmsg_level = SOL_SOCKET;
      cmsg.hdr.cmsg_type = SCM_CREDS;
  #endif
  
  retry:
 -#if defined(HAVE_CMSGCRED) && !defined(LOCAL_CREDS)
 +#if defined(HAVE_CMSGCRED) && (!defined(LOCAL_CREDS) || defined(__FreeBSD__))
      written = sendmsg(fd, &msg, 0);
  #else
      written = write(fd, &data[0], 1);
 @@ -654,15 +667,20 @@
      gid_t c_gid;
  
  #ifdef HAVE_CMSGCRED
 -    struct {
 +    struct cmsgcred *cred;
 +    union {
  	    struct cmsghdr hdr;
 -	    struct cmsgcred cred;
 +	    char cred[CMSG_SPACE (sizeof (struct cmsgcred))];
      } cmsg;
  #endif
  
 +#ifdef RUN_AS_EUID
 +    s_uid = geteuid();
 +#else
      s_uid = getuid();
 +#endif
  
 -#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED)
 +#if defined(LOCAL_CREDS) && defined(HAVE_CMSGCRED) && !defined(__FreeBSD__)
      /* Set the socket to receive credentials on the next message */
      {
          int on = 1;
 @@ -683,8 +701,8 @@
  
  #ifdef HAVE_CMSGCRED
      memset(&cmsg, 0, sizeof(cmsg));
 -    msg.msg_control = &cmsg;
 -    msg.msg_controllen = sizeof(cmsg);
 +    msg.msg_control = (caddr_t) &cmsg;
 +    msg.msg_controllen = CMSG_SPACE (sizeof (struct cmsgcred));
  #endif
  
  retry:
 @@ -701,7 +719,7 @@
          goto failed;
      }
  #ifdef HAVE_CMSGCRED
 -    if (cmsg.hdr.cmsg_len < sizeof(cmsg) || cmsg.hdr.cmsg_type != SCM_CREDS) {
 +    if (cmsg.hdr.cmsg_len < CMSG_LEN (sizeof (struct cmsgcred)) || cmsg.hdr.cmsg_type != SCM_CREDS) {
          GAM_DEBUG(DEBUG_INFO,
                    "Message from recvmsg() was not SCM_CREDS\n");
          goto failed;
 @@ -727,9 +745,10 @@
              goto failed;
          }
  #elif defined(HAVE_CMSGCRED)
 -        c_pid = cmsg.cred.cmcred_pid;
 -        c_uid = cmsg.cred.cmcred_euid;
 -        c_gid = cmsg.cred.cmcred_groups[0];
 +        cred = (struct cmsgcred *) CMSG_DATA (&cmsg);
 +        c_pid = cred->cmcred_pid;
 +        c_uid = cred->cmcred_euid;
 +        c_gid = cred->cmcred_groups[0];
  #else /* !SO_PEERCRED && !HAVE_CMSGCRED */
          GAM_DEBUG(DEBUG_INFO,
                    "Socket credentials not supported on this OS\n");
 @@ -1288,14 +1307,17 @@
  
      // FIXME: drop and reacquire lock while blocked?
      gamin_data_lock(conn);
 -    if (!gamin_data_event_ready(conn)) {
 +    while ((ret = gamin_data_event_ready(conn)) == 0) {
          if (gamin_read_data(conn, fc->fd, 1) < 0) {
  	    gamin_try_reconnect(conn, fc->fd);
  	    FAMErrno = FAM_CONNECT;
  	    return (-1);
  	}
      }
 -    ret = gamin_data_read_event(conn, fe);
 +
 +    if (ret > 0)
 +        ret = gamin_data_read_event(conn, fe);
 +
      gamin_data_unlock(conn);
  
      if (ret < 0) {
 --- libgamin/gam_fork.c.orig	2007-07-04 06:36:48.000000000 -0700
 +++ libgamin/gam_fork.c	2013-02-16 19:02:46.360093751 -0800
 @@ -42,6 +42,82 @@
      return NULL;
  }
  
 +#ifdef RUN_AS_EUID
 +/**
 + * gamin_drop_privileges
 + *
 + * Attempt to drop privileges to the effective uid and gid before
 + * forking a copy of the gamin server
 + * 
 + * Return 0 in case of success or -1 in case of detected error.
 + */
 +int
 +gamin_drop_privileges(void)
 +{
 +    GAM_DEBUG(DEBUG_INFO, "Dropping privileges to effective user and group\n");
 +
 +    /* get the current real user and group */
 +    int from_uid = getuid();
 +    int from_gid = getgid();
 +
 +    /* get the effective user and group */
 +    int to_uid = geteuid();
 +    int to_gid = getegid();
 +
 +    /* make sure we were able to get the user and group values */
 +    if ( from_uid == -1 || to_uid == -1 || from_gid == -1 || to_gid == -1 ) {
 +        gam_error(DEBUG_INFO, "failed to get user or group info, unable to drop privileges\n");
 +        return(-1);
 +    }
 +
 +    /* refuse to run setuid if it would escalate privileges */
 +    if ( from_uid != 0 && to_uid == 0 )
 +    {
 +        gam_error(DEBUG_INFO, "refusing to escalate user privileges from=%d to=%d\n", from_uid, to_uid);
 +        return(-1);
 +    }
 +
 +    /* refuse to run setgid if it would escalate privileges */
 +    if ( from_gid != 0 && to_gid == 0 )
 +    {
 +        gam_error(DEBUG_INFO, "refusing to escalate group privileges from=%d to=%d\n", from_gid, to_gid);
 +        return(-1);
 +    }
 +
 +    /* run setuid to drop privileges to the effective user */
 +    if ( from_uid != to_uid ) {
 +        GAM_DEBUG(DEBUG_INFO, "Attempting setuid from=%d to=%d\n", from_uid, to_uid);
 +
 +        /* run setuid and check for errors */
 +        if (setuid(to_uid) == -1) {
 +            gam_error(DEBUG_INFO, "failed to run setuid from=%d to=%d\n", from_uid, to_uid);
 +            return(-1);
 +        }
 +    }
 +    else {
 +        GAM_DEBUG(DEBUG_INFO, "Already running as effective user, skipping setuid\n");
 +    }
 +
 +    /* run setgid to drop privileges to the effective group */
 +    if ( from_gid != to_gid ) {
 +        GAM_DEBUG(DEBUG_INFO, "Attempting setgid from=%d to=%d\n", from_gid, to_gid);
 +
 +        /* run setuid and check for errors */
 +        if (setgid(to_gid) == -1) {
 +            gam_error(DEBUG_INFO, "failed to run setgid from=%d to=%d\n", from_uid, to_uid);
 +            return(-1);
 +        }
 +    }
 +    else {
 +        GAM_DEBUG(DEBUG_INFO, "Already running as effective group, skipping setgid\n");
 +    }
 +
 +    GAM_DEBUG(DEBUG_INFO, "Succeeded in dropping privileges from %d:%d to %d:%d\n", from_uid, from_gid, to_uid, to_gid);
 +
 +    return(0);
 +}
 +#endif
 +
  /**
   * gamin_fork_server:
   * @fam_client_id: the client ID string to use
 @@ -71,6 +147,14 @@
          long open_max;
  	long i;
  
 +#ifdef RUN_AS_EUID
 +        /* Drop privileges to the current uid/gid and return on failure */
 +        if(gamin_drop_privileges() == -1)
 +        {
 +            return(-1);
 +        }
 +#endif
 +
          /* don't hold open fd opened from the client of the library */
  	open_max = sysconf (_SC_OPEN_MAX);
  	for (i = 0; i < open_max; i++)
 --- libgamin/gam_fork.h.orig	2007-07-04 06:36:48.000000000 -0700
 +++ libgamin/gam_fork.h	2013-02-16 18:55:08.220102407 -0800
 @@ -32,6 +32,9 @@
  #endif
  
  int		gamin_fork_server	(const char *fam_client_id);
 +#ifdef RUN_AS_EUID
 +int		gamin_drop_privileges	(void);
 +#endif
  
  #ifdef __cplusplus
  }
 
 --------------090305060503020705000402--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201302170430.r1H4U1d0094279>