]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - support/nsm/file.c
libnsm.a: Replace __attribute_noinline__
[nfs-utils.git] / support / nsm / file.c
index 8796705918545b95007628930999ded4eaae8379..4714bbf50f2d7bedf9a662887c20c29705a145da 100644 (file)
 #endif
 
 #include <sys/types.h>
+#ifdef HAVE_SYS_CAPABILITY_H
+#include <sys/capability.h>
+#endif
+#include <sys/prctl.h>
 #include <sys/stat.h>
 
 #include <ctype.h>
@@ -122,7 +126,7 @@ exact_error_check(const ssize_t len, const size_t buflen)
  * containing an appropriate pathname, or NULL if an error
  * occurs.  Caller must free the returned result with free(3).
  */
-__attribute_malloc__
+__attribute__((__malloc__))
 static char *
 nsm_make_record_pathname(const char *directory, const char *hostname)
 {
@@ -170,7 +174,7 @@ nsm_make_record_pathname(const char *directory, const char *hostname)
  * containing an appropriate pathname, or NULL if an error
  * occurs.  Caller must free the returned result with free(3).
  */
-__attribute_malloc__
+__attribute__((__malloc__))
 static char *
 nsm_make_pathname(const char *directory)
 {
@@ -200,7 +204,7 @@ nsm_make_pathname(const char *directory)
  * containing an appropriate pathname, or NULL if an error
  * occurs.  Caller must free the returned result with free(3).
  */
-__attribute_malloc__
+__attribute__((__malloc__))
 static char *
 nsm_make_temp_pathname(const char *pathname)
 {
@@ -335,6 +339,36 @@ nsm_is_default_parentdir(void)
        return strcmp(nsm_base_dirname, NSM_DEFAULT_STATEDIR) == 0;
 }
 
+/*
+ * Clear all capabilities but CAP_NET_BIND_SERVICE.  This permits
+ * callers to acquire privileged source ports, but all other root
+ * capabilities are disallowed.
+ *
+ * Returns true if successful, or false if some error occurred.
+ */
+static _Bool
+nsm_clear_capabilities(void)
+{
+#ifdef HAVE_SYS_CAPABILITY_H
+       cap_t caps;
+
+       caps = cap_from_text("cap_net_bind_service=ep");
+       if (caps == NULL) {
+               xlog(L_ERROR, "Failed to allocate capability: %m");
+               return false;
+       }
+
+       if (cap_set_proc(caps) == -1) {
+               xlog(L_ERROR, "Failed to set capability flags: %m");
+               (void)cap_free(caps);
+               return false;
+       }
+
+       (void)cap_free(caps);
+#endif
+       return true;
+}
+
 /**
  * nsm_drop_privileges - drop root privileges
  * @pidfd: file descriptor of a pid file
@@ -382,6 +416,14 @@ nsm_drop_privileges(const int pidfd)
                if (fchown(pidfd, st.st_uid, st.st_gid) == -1)
                        xlog_warn("Failed to change owner of pidfile: %m");
 
+       /*
+        * Don't clear capabilities when dropping root.
+        */
+        if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
+                xlog(L_ERROR, "prctl(PR_SET_KEEPCAPS) failed: %m");
+               return 0;
+       }
+
        if (setgroups(0, NULL) == -1) {
                xlog(L_ERROR, "Failed to drop supplementary groups: %m");
                return false;
@@ -399,7 +441,8 @@ nsm_drop_privileges(const int pidfd)
        }
 
        xlog(D_CALL, "Effective UID, GID: %u, %u", st.st_uid, st.st_gid);
-       return true;
+
+       return nsm_clear_capabilities();
 }
 
 /**
@@ -591,7 +634,7 @@ nsm_priv_to_hex(const char *priv, char *buf, const size_t buflen)
 /*
  * Returns the length in bytes of the created record.
  */
-__attribute_noinline__
+__attribute__((__noinline__))
 static size_t
 nsm_create_monitor_record(char *buf, const size_t buflen,
                const struct sockaddr *sap, const struct mon *m)
@@ -741,7 +784,7 @@ out:
        return result;
 }
 
-__attribute_noinline__
+__attribute__((__noinline__))
 static _Bool
 nsm_parse_line(char *line, struct sockaddr_in *sin, struct mon *m)
 {