cifs.upcall: drop capabilities early in program
authorJeff Layton <jlayton@samba.org>
Wed, 15 Feb 2017 15:00:45 +0000 (10:00 -0500)
committerJeff Layton <jlayton@samba.org>
Wed, 15 Feb 2017 16:07:01 +0000 (11:07 -0500)
Much of cifs.upcall can and should be run without elevated privileges.
On entry into the program, drop as many capabilities as we can get away
with, and then always drop any remaining caps after calling setuid().

Signed-off-by: Jeff Layton <jlayton@samba.org>
Makefile.am
cifs.upcall.c

index 2e99e601049ae1c75c9ead294173d82495251e02..4823b63810824612de95acbea68f7e67b62d8f71 100644 (file)
@@ -16,7 +16,7 @@ clean-local: clean-local-upcall clean-local-idmap clean-local-cifsacl
 if CONFIG_CIFSUPCALL
 sbin_PROGRAMS += cifs.upcall
 cifs_upcall_SOURCES = cifs.upcall.c data_blob.c asn1.c spnego.c
-cifs_upcall_LDADD = -ltalloc -lkeyutils $(KRB5_LDADD)
+cifs_upcall_LDADD = -ltalloc -lkeyutils $(KRB5_LDADD) $(CAPNG_LDADD)
 man_MANS += cifs.upcall.8
 
 #
index 2b535a133a30abaa64cd59d5137ab988c32b9057..0bd3dcb1600a4a0f8b60271c299e804e25370563 100644 (file)
 #include "spnego.h"
 #include "cifs_spnego.h"
 
+#ifdef HAVE_LIBCAP_NG
+#include <cap-ng.h>
+#endif
+
 static krb5_context    context;
 static const char      *prog = "cifs.upcall";
 
@@ -63,6 +67,59 @@ typedef enum _sectype {
        MS_KRB5
 } sectype_t;
 
+#ifdef HAVE_LIBCAP_NG
+static int
+trim_capabilities(bool need_ptrace)
+{
+       capng_clear(CAPNG_SELECT_BOTH);
+
+       /*
+        * Need PTRACE and DAC_OVERRIDE for environment scraping, SETGID to
+        * change gid and grouplist, and SETUID to change uid.
+        */
+       if (capng_updatev(CAPNG_ADD, CAPNG_PERMITTED|CAPNG_EFFECTIVE,
+                       CAP_SETUID, CAP_SETGID, CAP_DAC_OVERRIDE, -1)) {
+               syslog(LOG_ERR, "%s: Unable to update capability set: %m\n", __func__);
+               return 1;
+       }
+
+       if (need_ptrace &&
+           capng_update(CAPNG_ADD, CAPNG_PERMITTED|CAPNG_EFFECTIVE, CAP_SYS_PTRACE)) {
+               syslog(LOG_ERR, "%s: Unable to update capability set: %m\n", __func__);
+               return 1;
+       }
+
+       if (capng_apply(CAPNG_SELECT_BOTH)) {
+               syslog(LOG_ERR, "%s: Unable to apply capability set: %m\n", __func__);
+               return 1;
+       }
+       return 0;
+}
+
+static int
+drop_all_capabilities(void)
+{
+       capng_clear(CAPNG_SELECT_BOTH);
+       if (capng_apply(CAPNG_SELECT_BOTH)) {
+               syslog(LOG_ERR, "%s: Unable to apply capability set: %m\n", __func__);
+               return 1;
+       }
+       return 0;
+}
+#else /* HAVE_LIBCAP_NG */
+static int
+trim_capabilities(void)
+{
+       return 0;
+}
+
+static int
+drop_all_capabilities(void)
+{
+       return 0;
+}
+#endif /* HAVE_LIBCAP_NG */
+
 /*
  * smb_krb5_principal_get_realm
  *
@@ -733,6 +790,9 @@ int main(const int argc, char *const argv[])
                }
        }
 
+       if (trim_capabilities(false))
+               goto out;
+
        /* is there a key? */
        if (argc <= optind) {
                usage();
@@ -837,6 +897,10 @@ int main(const int argc, char *const argv[])
                goto out;
        }
 
+       rc = drop_all_capabilities();
+       if (rc)
+               goto out;
+
        rc = krb5_init_context(&context);
        if (rc) {
                syslog(LOG_ERR, "unable to init krb5 context: %ld", rc);