diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2010-01-14 12:24:34 -0500 |
---|---|---|
committer | Steve Dickson <steved@redhat.com> | 2010-01-15 14:55:52 -0500 |
commit | e2446fda6e7cdb1b9462162b81b0e50fd6efaf56 (patch) | |
tree | f1a6bedafb0fc506cc0cccd8848a13d421a70afb /support | |
parent | d16bd0400fc096ec2fed36d5dfa8620b2370e4d1 (diff) | |
download | nfs-utils-e2446fda6e7cdb1b9462162b81b0e50fd6efaf56.tar.gz nfs-utils-e2446fda6e7cdb1b9462162b81b0e50fd6efaf56.tar.xz nfs-utils-e2446fda6e7cdb1b9462162b81b0e50fd6efaf56.zip |
libnsm.a: retain CAP_NET_BIND when dropping privileges
I'm about to switch the order of listener creation and dropping root
privileges. rpc.statd will drop privileges first, then create its
listeners. The reason for the new ordering is explained in a
subsequent patch.
However, for non-TI-RPC builds, rpc_init() needs to use a privileged
port to do pmap registrations. For both TI-RPC and non-TI-RPC builds,
CAP_NET_BIND is required in case the admin requests a privileged
listener port on the statd command line.
So that these requirements are met, nsm_drop_privileges() will now
retain CAP_NET_BIND while dropping root.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Diffstat (limited to 'support')
-rw-r--r-- | support/nsm/file.c | 41 |
1 files changed, 40 insertions, 1 deletions
diff --git a/support/nsm/file.c b/support/nsm/file.c index 8796705..d469219 100644 --- a/support/nsm/file.c +++ b/support/nsm/file.c @@ -67,6 +67,8 @@ #endif #include <sys/types.h> +#include <sys/capability.h> +#include <sys/prctl.h> #include <sys/stat.h> #include <ctype.h> @@ -335,6 +337,34 @@ 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) +{ + 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); + return true; +} + /** * nsm_drop_privileges - drop root privileges * @pidfd: file descriptor of a pid file @@ -382,6 +412,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 +437,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(); } /** |