* [PATCH] nfs-utils - 1 of 6 - statd - drop privs
@ 2003-06-18 17:33 Steve Dickson
2003-07-02 6:17 ` Neil Brown
0 siblings, 1 reply; 5+ messages in thread
From: Steve Dickson @ 2003-06-18 17:33 UTC (permalink / raw)
To: nfs
[-- Attachment #1: Type: text/plain, Size: 355 bytes --]
The following 6 patches have been ported to the
1.0.3 release the nfs-utils package. I'm hopefully
that Neil will incorate these so I no longer
have to continue porting them... ;-)
This first patch allows statd to run as a non-root
user. If there is not an rpcuser account (which
there is in our world) it will try to use the
nobody account.
SteveD.
[-- Attachment #2: nfs-utils-1.0.3-01-statd-dropprivs.patch --]
[-- Type: text/plain, Size: 3534 bytes --]
--- ./utils/statd/statd.c.orig 2003-06-02 14:57:03.000000000 -0400
+++ ./utils/statd/statd.c 2003-06-02 14:57:15.000000000 -0400
@@ -17,6 +17,10 @@
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#include <rpcmisc.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <fcntl.h>
#include "statd.h"
#include "version.h"
@@ -34,6 +38,7 @@
char * SM_BAK_DIR = DEFAULT_SM_BAK_DIR;
char * SM_STAT_PATH = DEFAULT_SM_STAT_PATH;
+
/* ----- end of state directory path stuff ------- */
short int restart = 0;
@@ -66,6 +71,47 @@
extern void simulator (int, char **);
#endif
+/*
+ * Privilege dropper
+ */
+static void
+drop_privs(void)
+{
+ /* First locate user to jump to */
+ /* Prefer _not_ to use nobody as we'll own some files */
+ struct passwd* pw;
+
+ pw = getpwnam(RUN_AS_USER);
+ if (pw == NULL)
+ {
+ /* i.e. nobody */
+ log (L_WARNING, "Warning: You should really create user %s\n",
+ RUN_AS_USER);
+ pw = getpwnam(RUN_AS_FALLBACK);
+ }
+ if (pw == NULL)
+ {
+ die("Cannot start - cannot drop privs: getpwnam()\n");
+ }
+
+ initgroups(pw->pw_name, pw->pw_gid);
+
+ setgid(pw->pw_gid);
+ setuid(pw->pw_uid);
+
+ if (getgid() == 0)
+ {
+ die("Cannot start - cannot drop privs: getgid()\n");
+ }
+ else if (getuid() == 0)
+ {
+ die("Cannot start - cannot drop privs: getuid()\n");
+ }
+
+ /* Good enough */
+}
+
+
#ifdef HAVE_TCP_WRAPPER
#include "tcpwrapper.h"
@@ -264,8 +310,6 @@
daemon mode. */
}
- log_init (name_p,version_p);
-
log_modes();
#ifdef SIMULATIONS
@@ -298,6 +342,8 @@
}
}
+ log_init (name_p, version_p);
+
/* Child. */
signal (SIGHUP, killer);
signal (SIGINT, killer);
@@ -305,9 +351,33 @@
/* WARNING: the following works on Linux and SysV, but not BSD! */
signal(SIGCHLD, SIG_IGN);
+
+ /* cevans - we're going to drop root privs, but before we do that,
+ * make sure to get our port <1024 socket
+ */
+
+ /* Insist on starting as root - this means that when we setuid() away
+ * from root, we'll keep current->dumpable=0 and prevent being messed
+ * with (we may revert to user "nobody" - it's better than root
+ */
+ if (getuid() != 0)
+ die("Startup failed: Please start rpc.statd as root\n");
+
+ /* Arm the ****** resolver before chroot() so it doesn't fail
+ * trying to open /etc/ for the dozenth time
+ */
+ sethostent(1);
+
/* initialize out_port */
statd_get_socket(out_port);
+ /* Drop privs */
+ drop_privs();
+
+ /* After dropping privs, verify we can access all the files we need */
+ if (access(".", R_OK|W_OK|X_OK) != 0)
+ die("Cannot access current directory after dropping privs: access()\n");
+
for (;;) {
if (!(run_mode & MODE_NOTIFY_ONLY)) {
/* Do not do pmap_unset() when running in notify mode.
--- ./utils/statd/statd.h.orig 2003-06-02 14:57:03.000000000 -0400
+++ ./utils/statd/statd.h 2003-06-02 15:00:10.000000000 -0400
@@ -10,3 +10,10 @@
#include "system.h"
#include "log.h"
+/* Users we try and run as (prefer non-nobody because nobody is overloaded */
+/* Also, the user we run as will own some important nfs state files */
+#define RUN_AS_USER "rpcuser"
+/* Bah */
+#define RUN_AS_FALLBACK "nobody"
+
+
--- ./utils/statd/log.c.orig 2003-06-02 14:57:03.000000000 -0400
+++ ./utils/statd/log.c 2003-06-02 14:57:15.000000000 -0400
@@ -32,7 +32,7 @@
void log_init()
{
if (!(run_mode & MODE_LOG_STDERR))
- openlog(name_p, LOG_PID, LOG_DAEMON);
+ openlog(name_p, LOG_PID | LOG_NDELAY, LOG_DAEMON);
mypid = getpid();
^ permalink raw reply [flat|nested] 5+ messages in thread* Re: [PATCH] nfs-utils - 1 of 6 - statd - drop privs 2003-06-18 17:33 [PATCH] nfs-utils - 1 of 6 - statd - drop privs Steve Dickson @ 2003-07-02 6:17 ` Neil Brown 2003-07-03 11:42 ` Steve Dickson 0 siblings, 1 reply; 5+ messages in thread From: Neil Brown @ 2003-07-02 6:17 UTC (permalink / raw) To: Steve Dickson; +Cc: nfs On Wednesday June 18, SteveD@redhat.com wrote: > The following 6 patches have been ported to the > 1.0.3 release the nfs-utils package. I'm hopefully > that Neil will incorate these so I no longer > have to continue porting them... ;-) Sorry for not looking at these sooner... > > > This first patch allows statd to run as a non-root > user. If there is not an rpcuser account (which > there is in our world) it will try to use the > nobody account. An effect of this patch is that if someone does a 'make install', statd won't work anymore without some chowning. What would you think if just getting stat to run as whichever users owns /var/lib/nfs, and printing a warning if it is root. Also the patch makes references to 'chroot' but never actually uses chroot. The second patch uses: /var/run/rpc.statd/rpc.statd.pid as a pid file, which doesn't seem like the right sort of name. Either /var/run/rpc.statd.pid or /var/run/nfs/rpc.statd.pid would seem more appropriate, or is there some RedHat standard you are following. If we did do a chroot in statd we wouldn't be able to remove the pid file any more. We could if it went in /var/lib/nfs, but I don't think that is the right place. Maybe if we held a fd of the pid file open and used ftruncate to remove the pid. Would that work ok? And I wish I knew why you thought mountd needed protection against SIGPIPE, though I guess it cannot hurt. NeilBrown ------------------------------------------------------- This SF.Net email sponsored by: Free pre-built ASP.NET sites including Data Reports, E-commerce, Portals, and Forums are available now. Download today and enter to win an XBOX or Visual Studio .NET. http://aspnet.click-url.com/go/psa00100006ave/direct;at.asp_061203_01/01 _______________________________________________ NFS maillist - NFS@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/nfs ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] nfs-utils - 1 of 6 - statd - drop privs 2003-07-02 6:17 ` Neil Brown @ 2003-07-03 11:42 ` Steve Dickson 2003-07-04 2:26 ` Neil Brown 0 siblings, 1 reply; 5+ messages in thread From: Steve Dickson @ 2003-07-03 11:42 UTC (permalink / raw) To: Neil Brown; +Cc: nfs Hello, Neil Brown wrote: >>This first patch allows statd to run as a non-root >>user. If there is not an rpcuser account (which >>there is in our world) it will try to use the >>nobody account. >> >> > >An effect of this patch is that if someone does a 'make install', >statd won't work anymore without some chowning. > True.... We do an adduser during the package installation... >What would you think if just getting stat to run as whichever users >owns /var/lib/nfs, and printing a warning if it is root. > Looking around it appears root owns /var/lib/nfs.. and the point of the patch is not to run a root..... I guess it all comes do to how secure you want statd.... security is never free.... :) Maybe you could add a compilation flag allowing people to control it that way... >The second patch uses: > /var/run/rpc.statd/rpc.statd.pid >as a pid file, which doesn't seem like the right sort of name. >Either > /var/run/rpc.statd.pid >or > /var/run/nfs/rpc.statd.pid > >would seem more appropriate, or is there some RedHat standard you are >following. > I had to make it a directory so the pid file could be removed after the privs have been dropped (i.e. not longer running as root). >If we did do a chroot in statd we wouldn't be able to remove the pid >file any more. We could if it went in /var/lib/nfs, but I don't think >that is the right place. > >Maybe if we held a fd of the pid file open and used ftruncate to >remove the pid. Would that work ok? > The privs dropping patch (i.e the first patch) makes the chroot no longer necessary... but holding might work but how would the unlink occur? >And I wish I knew why you thought mountd needed protection against >SIGPIPE, though I guess it cannot hurt. > TCP aborts.... If a sender has a socket open and the receiver close()s the socket with data still unread, the sender gets a SIGPIPE. SteveD. ------------------------------------------------------- This SF.Net email sponsored by: Free pre-built ASP.NET sites including Data Reports, E-commerce, Portals, and Forums are available now. Download today and enter to win an XBOX or Visual Studio .NET. http://aspnet.click-url.com/go/psa00100006ave/direct;at.asp_061203_01/01 _______________________________________________ NFS maillist - NFS@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/nfs ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] nfs-utils - 1 of 6 - statd - drop privs 2003-07-03 11:42 ` Steve Dickson @ 2003-07-04 2:26 ` Neil Brown 2003-07-04 4:26 ` Neil Brown 0 siblings, 1 reply; 5+ messages in thread From: Neil Brown @ 2003-07-04 2:26 UTC (permalink / raw) To: Steve Dickson; +Cc: nfs On Thursday July 3, SteveD@RedHat.com wrote: > >An effect of this patch is that if someone does a 'make install', > >statd won't work anymore without some chowning. > > > True.... We do an adduser during the package installation... > > >What would you think if just getting stat to run as whichever users > >owns /var/lib/nfs, and printing a warning if it is root. > > > Looking around it appears root owns /var/lib/nfs.. and the > point of the patch is not to run a root..... I guess it all comes > do to how secure you want statd.... security is never free.... :) > Maybe you could add a compilation flag allowing people > to control it that way... I had assumed that /var/lib/nfs would need to be chowned to "rpcuser" for statd to work, but I guess it doesn't. However "state", "sm" and "sm.bak" must already exist and be owned by whoever state runs as. So this is what I think I will do: If 'sm' exists, statd takes on the identity of the owner, otherwise it takes on the identity of the owner of /var/lib/nfs. The "make install" script creates state, sm, and sm.bak and chowns them to $SOMEUSER The configure script sets $SOMEUSER to rpcuser if that is in /etc/passwd, or nobody, but this setting can be over-ridden via a config option statd will create /var/run/rpc.statd.pid as root and will keep and open filehandle for it to ftruncate later. Scripts which check for this existance of the need to [ -s /var/run/rpc.statd.pid ] This allows for trouble free upgrading, a normal pid filename, and still allows and even encourages good security. > >And I wish I knew why you thought mountd needed protection against > >SIGPIPE, though I guess it cannot hurt. > > > TCP aborts.... If a sender has a socket open and the receiver close()s the > socket with data still unread, the sender gets a SIGPIPE. Arh, that makes sense. The patch has already gone in anyway. NeilBrown ------------------------------------------------------- This SF.Net email sponsored by: Free pre-built ASP.NET sites including Data Reports, E-commerce, Portals, and Forums are available now. Download today and enter to win an XBOX or Visual Studio .NET. http://aspnet.click-url.com/go/psa00100006ave/direct;at.asp_061203_01/01 _______________________________________________ NFS maillist - NFS@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/nfs ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] nfs-utils - 1 of 6 - statd - drop privs 2003-07-04 2:26 ` Neil Brown @ 2003-07-04 4:26 ` Neil Brown 0 siblings, 0 replies; 5+ messages in thread From: Neil Brown @ 2003-07-04 4:26 UTC (permalink / raw) To: Steve Dickson; +Cc: nfs On Friday July 4, neilb@cse.unsw.edu.au wrote: > So this is what I think I will do: > > If 'sm' exists, statd takes on the identity of the owner, otherwise > it takes on the identity of the owner of /var/lib/nfs. > The "make install" script creates state, sm, and sm.bak and chowns > them to $SOMEUSER > The configure script sets $SOMEUSER to rpcuser if that is in > /etc/passwd, or nobody, but this setting can be over-ridden via a > config option > > statd will create /var/run/rpc.statd.pid as root and will keep and > open filehandle for it to ftruncate later. Scripts which check > for this existance of the need to > [ -s /var/run/rpc.statd.pid ] Ok, I've just commited the following patch (plus new configure generated by autoconf) to nfs-utils CVS. Hopefully it does most of what you need. Are you interested in submitting your current 'rc' scripts or an updated .spec file? NeilBrown 2003-07-04 NeilBrown <neilb@cse.unsw.edu.au> Steve Dickson <SteveD@redhat.com> statd cleanup: * utils/statd/statd.c: create a pidfile with pid of statd, and truncate it when statd exists. * utils/statd/statd.c: drop privs by setuid to owner of SM_DIR, and warn if this is root. * utils/statd/statd.c: when statd forks, connect child to parent with a pipe, and send a byte down the pipe once the child is working properly. * Makefile: create and chown sm, sm.bak, state when "make install" * configure.in: add --with-statduser= option which defaults to "rpcuser" or "nobody" * config.mk.in: pass "statduser" through to Makefile Index: Makefile =================================================================== RCS file: /cvsroot/nfs/nfs-utils/Makefile,v retrieving revision 1.1.1.1 diff -u -r1.1.1.1 Makefile --- Makefile 18 Oct 1999 23:21:12 -0000 1.1.1.1 +++ Makefile 4 Jul 2003 04:15:00 -0000 @@ -20,3 +20,7 @@ touch $(STATEDIR)/xtab; chmod 644 $(STATEDIR)/xtab touch $(STATEDIR)/etab; chmod 644 $(STATEDIR)/etab touch $(STATEDIR)/rmtab; chmod 644 $(STATEDIR)/rmtab + mkdir -p $(STATEDIR)/sm $(STATEDIR)/sm.bak + touch $(STATEDIR)/state + chmod go-rwx $(STATEDIR)/sm $(STATEDIR)/sm.bak $(STATEDIR)/state + chown $(STATDUSER) $(STATEDIR)/sm $(STATEDIR)/sm.bak $(STATEDIR)/state Index: config.mk.in =================================================================== RCS file: /cvsroot/nfs/nfs-utils/config.mk.in,v retrieving revision 1.8 diff -u -r1.8 config.mk.in --- config.mk.in 3 Jul 2003 06:14:10 -0000 1.8 +++ config.mk.in 4 Jul 2003 04:15:00 -0000 @@ -10,6 +10,7 @@ SBINDIR = @sbindir@ MANDIR = @mandir@ STATEDIR = $(install_prefix)@statedir@ +STATDUSER = @statduser@ ################################################################## # This is the prefix that will be used for nfsd and mountd. Leave this Index: configure.in =================================================================== RCS file: /cvsroot/nfs/nfs-utils/configure.in,v retrieving revision 1.35 diff -u -r1.35 configure.in --- configure.in 3 Jul 2003 02:37:15 -0000 1.35 +++ configure.in 4 Jul 2003 04:15:26 -0000 @@ -20,6 +20,15 @@ statedir=$withval, statedir=/var/lib/nfs) AC_SUBST(statedir) +AC_ARG_WITH(statduser, + [ --with-statduser=rpcuser user for statd to run under [rpcuser or nobody]], + statduser=$withval, + if grep -s '^rpcuser:' /etc/passwd > /dev/null; then + statduser=rpcuser + else + statduser=nobody + fi) + AC_SUBST(statduser) AC_ARG_ENABLE(nfsv3, [ --enable-nfsv3 enable support for NFSv3], enable_nfsv3=$enableval, Index: utils/statd/log.c =================================================================== RCS file: /cvsroot/nfs/nfs-utils/utils/statd/log.c,v retrieving revision 1.5 diff -u -r1.5 log.c --- utils/statd/log.c 17 Feb 2001 17:22:53 -0000 1.5 +++ utils/statd/log.c 4 Jul 2003 04:15:26 -0000 @@ -32,7 +32,7 @@ void log_init() { if (!(run_mode & MODE_LOG_STDERR)) - openlog(name_p, LOG_PID, LOG_DAEMON); + openlog(name_p, LOG_PID | LOG_NDELAY, LOG_DAEMON); mypid = getpid(); Index: utils/statd/statd.c =================================================================== RCS file: /cvsroot/nfs/nfs-utils/utils/statd/statd.c,v retrieving revision 1.13 diff -u -r1.13 statd.c --- utils/statd/statd.c 11 Oct 2002 06:17:59 -0000 1.13 +++ utils/statd/statd.c 4 Jul 2003 04:15:26 -0000 @@ -12,11 +12,13 @@ #include <signal.h> #include <unistd.h> #include <fcntl.h> +#include <errno.h> #include <string.h> #include <getopt.h> #include <rpc/rpc.h> #include <rpc/pmap_clnt.h> #include <rpcmisc.h> +#include <grp.h> #include "statd.h" #include "version.h" @@ -147,6 +149,57 @@ fprintf(stderr," -N Run in notify only mode.\n"); } +static const char *pidfile = "/var/run/rpc.statd.pid"; + +int pidfd = -1; +static void create_pidfile(void) +{ + FILE *fp; + + unlink(pidfile); + fp = fopen(pidfile, "w"); + if (!fp) + die("Opening %s failed: %s\n", + pidfile, strerror(errno)); + fprintf(fp, "%d\n", getpid()); + pidfd = dup(fileno(fp)); + if (fclose(fp) < 0) + log(L_WARNING, "Flushing pid file failed.\n"); +} + +static void truncate_pidfile(void) +{ + if (pidfd >= 0) + ftruncate(pidfd, 0); +} + +static void drop_privs(void) +{ + struct stat st; + + if (stat(SM_DIR, &st) == -1 && + stat(DIR_BASE, &st) == -1) + st.st_uid = 0; + + if (st.st_uid == 0) { + log(L_WARNING, "statd running as root. chown %s to choose different user\n", + SM_DIR); + return; + } + /* better chown the pid file before dropping, as if it + * if over nfs we might loose access + */ + if (pidfd >= 0) + fchown(pidfd, st.st_uid, st.st_gid); + + setgroups(0, NULL); + if (setgid(st.st_gid) == -1 + || setuid(st.st_uid) == -1) { + log(L_ERROR, "Fail to drop privileges"); + exit(1); + } +} + /* * Entry routine/main loop. */ @@ -157,6 +210,9 @@ int arg; int port = 0, out_port = 0; + int pipefds[2] = { -1, -1}; + char status; + /* Default: daemon mode, no other options */ run_mode = 0; @@ -264,10 +320,6 @@ daemon mode. */ } - log_init (name_p,version_p); - - log_modes(); - #ifdef SIMULATIONS if (argc > 1) /* LH - I _really_ need to update simulator... */ @@ -277,28 +329,54 @@ if (!(run_mode & MODE_NODAEMON)) { int filedes, fdmax, tempfd; + if (pipe(pipefds)<0) { + perror("statd: unable to create pipe"); + exit(1); + } if ((pid = fork ()) < 0) { - perror ("Could not fork"); + perror ("statd: Could not fork"); exit (1); } else if (pid != 0) { - /* Parent. */ + /* Parent. + * Wait for status from child. + */ + close(pipefds[1]); + if (read(pipefds[0], &status, 1) != 1) + exit(1); exit (0); } /* Child. */ + close(pipefds[0]); setsid (); - chdir (DIR_BASE); + if (chdir (DIR_BASE) == -1) { + perror("statd: Could not chdir"); + exit(1); + } + while (pipefds[1] <= 2) { + pipefds[1] = dup(pipefds[1]); + if (pipefds[1]<0) { + perror("statd: dup"); + exit(1); + } + } tempfd = open("/dev/null", O_RDWR); close(0); dup2(tempfd, 0); close(1); dup2(tempfd, 1); close(2); dup2(tempfd, 2); fdmax = sysconf (_SC_OPEN_MAX); - for (filedes = 3; filedes < fdmax; filedes++) { - close (filedes); - } + for (filedes = 3; filedes < fdmax; filedes++) + if (filedes != pipefds[1]) + close (filedes); + } /* Child. */ + + log_init (name_p,version_p); + + log_modes(); + signal (SIGHUP, killer); signal (SIGINT, killer); signal (SIGTERM, killer); @@ -308,6 +386,10 @@ /* initialize out_port */ statd_get_socket(out_port); + create_pidfile(); + atexit(truncate_pidfile); + drop_privs(); + for (;;) { if (!(run_mode & MODE_NOTIFY_ONLY)) { /* Do not do pmap_unset() when running in notify mode. @@ -319,6 +401,15 @@ } change_state (); shuffle_dirs (); /* Move directory names around */ + + /* If we got this far, we have successfully started, so notify parent */ + if (pipefds[1] > 0) { + status = 0; + write(pipefds[1], &status, 1); + close(pipefds[1]); + pipefds[1] = -1; + } + notify_hosts (); /* Send out notify requests */ ++restart; ------------------------------------------------------- This SF.Net email sponsored by: Free pre-built ASP.NET sites including Data Reports, E-commerce, Portals, and Forums are available now. Download today and enter to win an XBOX or Visual Studio .NET. http://aspnet.click-url.com/go/psa00100006ave/direct;at.asp_061203_01/01 _______________________________________________ NFS maillist - NFS@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/nfs ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2003-07-04 4:26 UTC | newest] Thread overview: 5+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2003-06-18 17:33 [PATCH] nfs-utils - 1 of 6 - statd - drop privs Steve Dickson 2003-07-02 6:17 ` Neil Brown 2003-07-03 11:42 ` Steve Dickson 2003-07-04 2:26 ` Neil Brown 2003-07-04 4:26 ` Neil Brown
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.