Allow the daemon to run as a non-root user after opening the control device
- which will also make the kernel driver run as the same non-root user
since it borrows the daemons credentials.

This requires a fix to the cachefiles kernel driver to make it set the mode
on files in creates to 0600.

This also requires the SELinux policy to be changed so that cachefilesd can
access /etc/passwd, otherwise only numeric uids and gids can be set.

Signed-off-by: David Howells <dhowe...@redhat.com>
---
 cachefilesd.c      |   59 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 cachefilesd.conf.5 |    7 ++++++
 2 files changed, 64 insertions(+), 2 deletions(-)

diff --git a/cachefilesd.c b/cachefilesd.c
index 6c435f6..81bb87d 100644
--- a/cachefilesd.c
+++ b/cachefilesd.c
@@ -48,6 +48,7 @@
 #include <poll.h>
 #include <limits.h>
 #include <grp.h>
+#include <pwd.h>
 #include <sys/inotify.h>
 #include <sys/time.h>
 #include <sys/vfs.h>
@@ -121,6 +122,8 @@ static unsigned long long brun, bcull, bstop, frun, fcull, 
fstop;
 static unsigned long long b_resume_threshold = ULLONG_MAX;
 static unsigned long long f_resume_threshold = 5;
 
+static uid_t daemon_uid;
+static gid_t daemon_gid;
 static const gid_t group_list[0];
 
 #define cachefd 3
@@ -489,6 +492,47 @@ int main(int argc, char *argv[])
                        continue;
                }
 
+               /* Note UID to run as. */
+               if (memcmp(cp, "uid", 3) == 0 && isspace(cp[3])) {
+                       struct passwd *pwd;
+                       char *end;
+
+                       for (cp += 3; isspace(*cp); cp++) {;}
+                       if (!*cp)
+                               cfgerror("Error parsing username/uid");
+
+                       daemon_uid = strtoul(cp, &end, 10);
+                       if (*end) {
+                               pwd = getpwnam(cp);
+                               if (!pwd)
+                                       oserror("Couldn't look up username/uid 
'%s'", cp);
+                               daemon_uid = pwd->pw_uid;
+                               daemon_gid = pwd->pw_gid;
+                       } else {
+                               daemon_gid = -1;
+                       }
+                       continue;
+               }
+
+               /* Note GID to run as. */
+               if (memcmp(cp, "gid", 3) == 0 && isspace(cp[3])) {
+                       struct group *grp;
+                       char *end;
+
+                       for (cp += 3; isspace(*cp); cp++) {;}
+                       if (!*cp)
+                               cfgerror("Error parsing group name/gid");
+
+                       daemon_gid = strtoul(cp, &end, 10);
+                       if (*end) {
+                               grp = getgrnam(cp);
+                               if (!grp)
+                                       oserror("Couldn't look up group 
name/gid '%s'", cp);
+                               daemon_gid = grp->gr_gid;
+                       }
+                       continue;
+               }
+
                /* note the dir command */
                if (memcmp(cp, "dir", 3) == 0 && isspace(cp[3])) {
                        char *sp;
@@ -545,13 +589,24 @@ int main(int argc, char *argv[])
        if (nullfd != 1)
                dup2(nullfd, 1);
 
-       for (loop = 4; loop < open_max; loop++)
-               close(loop);
+       if (close_range(4, open_max, 0) == -1) {
+               for (loop = 4; loop < open_max; loop++)
+                       close(loop);
+       }
 
        /* set up a connection to syslog whilst we still can (the bind command
         * will give us our own namespace with no /dev/log */
        openlog("cachefilesd", LOG_PID, LOG_DAEMON);
        xopenedlog = true;
+
+       if (daemon_uid || daemon_gid) {
+               info("Setting credentials");
+               if (setresgid(daemon_gid, daemon_gid, daemon_gid) < 0)
+                       oserror("Unable to set GID to %d", daemon_gid);
+               if (setresuid(daemon_uid, daemon_uid, daemon_uid) < 0)
+                       oserror("Unable to set UID to %d", daemon_uid);
+       }
+
        info("About to bind cache");
 
        /* now issue the bind command */
diff --git a/cachefilesd.conf.5 b/cachefilesd.conf.5
index b108bdc..534b8f0 100644
--- a/cachefilesd.conf.5
+++ b/cachefilesd.conf.5
@@ -35,6 +35,13 @@ access the cache.  The default is to use cachefilesd's 
security context.  Files
 will be created in the cache with the label of directory specified to the 'dir'
 command.
 .TP
+.B uid <id>
+.TP
+.B gid <id>
+Set the UID or GID that the daemon runs as to the specified ID.  The ID can be
+given as a number or as a name.  The base cache directory and all the
+directories and files under it must be owned by these IDs.
+.TP
 .B brun <N>%
 .TP
 .B bcull <N>%
--
Linux-cachefs mailing list
Linux-cachefs@redhat.com
https://listman.redhat.com/mailman/listinfo/linux-cachefs

Reply via email to