ports/176203: [patch] devel/gamin: Drop privileges to effective user and group
Danny Warren
danny at dannywarren.com
Sun Feb 17 04:50:02 UTC 2013
The following reply was made to PR ports/176203; it has been noted by GNATS.
From: Danny Warren <danny at dannywarren.com>
To: bug-followup at FreeBSD.org, danny at dannywarren.com
Cc:
Subject: Re: ports/176203: [patch] devel/gamin: Drop privileges to effective
user and group
Date: Sat, 16 Feb 2013 20:47:01 -0800
This is a multi-part message in MIME format.
--------------020205000508090601030105
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Alright, this should hopefully be the last change.
* fixed typo in setgid debug message
* reworked "gamin_drop_privileges" method to accept a uid and gid value
instead of assuming you always want the effective user, so that it can
be used in other parts of the code if needed
* changed call to "gamin_drop_privileges" to pass the effective uid/gid
after fork
--------------020205000508090601030105
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 20:37:31.298176973 -0800
@@ -42,6 +42,78 @@
return NULL;
}
+#ifdef RUN_AS_EUID
+/**
+ * gamin_drop_privileges
+ *
+ * Attempt to drop privileges to another user and group before forking
+ * a copy of the gam server
+ *
+ * Return 0 in case of success or -1 in case of detected error.
+ */
+int
+gamin_drop_privileges(int to_uid, int to_gid)
+{
+ GAM_DEBUG(DEBUG_INFO, "Dropping privileges to %d:%d before forking server\n", to_uid, to_gid);
+
+ /* Get the current real user and group */
+ int from_uid = getuid();
+ int from_gid = getgid();
+
+ /* 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_gid, to_gid);
+ 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 +143,13 @@
long open_max;
long i;
+#ifdef RUN_AS_EUID
+ /* Drop privileges to the current effective uid/gid and return on failure */
+ if(gamin_drop_privileges( geteuid(), getegid() ) == -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 20:38:00.328594608 -0800
@@ -32,6 +32,9 @@
#endif
int gamin_fork_server (const char *fam_client_id);
+#ifdef RUN_AS_EUID
+int gamin_drop_privileges (int to_uid, int to_gid);
+#endif
#ifdef __cplusplus
}
--------------020205000508090601030105--
More information about the freebsd-gnome
mailing list