[TS-2261] Add config option to restore/elevate access to reading files by root when loading plugins
Project: http://git-wip-us.apache.org/repos/asf/trafficserver/repo Commit: http://git-wip-us.apache.org/repos/asf/trafficserver/commit/fffb60ed Tree: http://git-wip-us.apache.org/repos/asf/trafficserver/tree/fffb60ed Diff: http://git-wip-us.apache.org/repos/asf/trafficserver/diff/fffb60ed Branch: refs/heads/5.0.x Commit: fffb60ed3bbc30cf302e0ccf956248cb1ec5cef3 Parents: 4102e98 Author: Bryan Call <[email protected]> Authored: Thu Oct 3 15:08:04 2013 -0700 Committer: Bryan Call <[email protected]> Committed: Thu Oct 3 15:08:04 2013 -0700 ---------------------------------------------------------------------- CHANGES | 3 ++ lib/ts/ink_cap.cc | 81 +++++++++++++++++++++++++++++++++++-- lib/ts/ink_cap.h | 47 +++++++++++++++++++++ mgmt/LocalManager.cc | 65 +---------------------------- mgmt/LocalManager.h | 6 --- mgmt/RecordsConfig.cc | 3 ++ mgmt/Rollback.cc | 2 +- proxy/Plugin.cc | 10 ++++- proxy/http/remap/UrlMapping.cc | 11 ++++- proxy/http/remap/UrlRewrite.cc | 28 ++++++++++--- 10 files changed, 173 insertions(+), 83 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fffb60ed/CHANGES ---------------------------------------------------------------------- diff --git a/CHANGES b/CHANGES index ee94a4b..cf1bff2 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,9 @@ -*- coding: utf-8 -*- Changes with Apache Traffic Server 4.1.0 + *) [TS-2261] Add config option to restore/elevate access to reading files by + root when loading plugins + *) [TS-2257] Healthcheck plugin can stop watching some events. *) [TS-2260] Avoid flooding log when log host is down. http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fffb60ed/lib/ts/ink_cap.cc ---------------------------------------------------------------------- diff --git a/lib/ts/ink_cap.cc b/lib/ts/ink_cap.cc index 038fc2e..e51b730 100644 --- a/lib/ts/ink_cap.cc +++ b/lib/ts/ink_cap.cc @@ -65,6 +65,7 @@ PreserveCapabilities() { # if TS_USE_POSIX_CAP zret = prctl(PR_SET_KEEPCAPS, 1); # endif + Debug("proxy_priv", "[PreserveCapabilities] zret : %d\n", zret); return zret; } @@ -75,14 +76,17 @@ RestrictCapabilities() { # if TS_USE_POSIX_CAP cap_t caps = cap_init(); // start with nothing. // Capabilities we need. - cap_value_t cap_list[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, CAP_IPC_LOCK }; - static int const CAP_COUNT = sizeof(cap_list)/sizeof(*cap_list); + cap_value_t perm_list[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, CAP_IPC_LOCK, CAP_DAC_OVERRIDE}; + static int const PERM_CAP_COUNT = sizeof(perm_list)/sizeof(*perm_list); + cap_value_t eff_list[] = { CAP_NET_ADMIN, CAP_NET_BIND_SERVICE, CAP_IPC_LOCK}; + static int const EFF_CAP_COUNT = sizeof(eff_list)/sizeof(*eff_list); - cap_set_flag(caps, CAP_PERMITTED, CAP_COUNT, cap_list, CAP_SET); - cap_set_flag(caps, CAP_EFFECTIVE, CAP_COUNT, cap_list, CAP_SET); + cap_set_flag(caps, CAP_PERMITTED, PERM_CAP_COUNT, perm_list, CAP_SET); + cap_set_flag(caps, CAP_EFFECTIVE, EFF_CAP_COUNT, eff_list, CAP_SET); zret = cap_set_proc(caps); cap_free(caps); # endif + Debug("proxy_priv", "[RestrictCapabilities] zret : %d\n", zret); return zret; } @@ -98,5 +102,74 @@ EnableCoreFile(bool flag) { Warning("Call to set PR_DUMPABLE was ineffective"); } # endif // linux check + Debug("proxy_priv", "[EnableCoreFile] zret : %d\n", zret); return zret; } + +#if TS_USE_POSIX_CAP +/** Control file access privileges to bypass DAC. + @parm state Use @c true to enable elevated privileges, + @c false to disable. + @return @c true if successful, @c false otherwise. + + @internal After some pondering I decided that the file access + privilege was worth the effort of restricting. Unlike the network + privileges this can protect a host system from programming errors + by not (usually) permitting such errors to access arbitrary + files. This is particularly true since none of the config files + current enable this feature so it's not actually called. Still, + best to program defensively and have it available. + */ +bool +elevateFileAccess(bool state) +{ + Debug("proxy_priv", "[elevateFileAccess] state : %d\n", state); + + bool zret = false; // return value. + cap_t cap_state = cap_get_proc(); // current capabilities + // Make a list of the capabilities we changed. + cap_value_t cap_list[] = { CAP_DAC_OVERRIDE }; + static int const CAP_COUNT = sizeof(cap_list)/sizeof(*cap_list); + + cap_set_flag(cap_state, CAP_EFFECTIVE, CAP_COUNT, cap_list, state ? CAP_SET : CAP_CLEAR); + zret = (0 == cap_set_proc(cap_state)); + cap_free(cap_state); + Debug("proxy_priv", "[elevateFileAccess] zret : %d\n", zret); + return zret; +} +#else +// bool removeRootPriv() +// +// - Returns true on success +// and false on failure +bool +removeRootPriv(uid_t euid) +{ + if (seteuid(euid) < 0) { + Debug("proxy_priv", "[removeRootPriv] seteuid failed : %s\n", strerror(errno)); + return false; + } + + Debug("proxy_priv", "[removeRootPriv] removed root privileges. Euid is %d\n", euid); + return true; +} + +// bool restoreRootPriv() +// +// - Returns true on success +// and false on failure +bool +restoreRootPriv(uid_t *old_euid) +{ + if (old_euid) + *old_euid = geteuid(); + if (seteuid(0) < 0) { + Debug("proxy_priv", "[restoreRootPriv] seteuid root failed : %s\n", strerror(errno)); + return false; + } + + Debug("proxy_priv", "[restoreRootPriv] restored root privileges. Euid is %d\n", 0); + + return true; +} +#endif http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fffb60ed/lib/ts/ink_cap.h ---------------------------------------------------------------------- diff --git a/lib/ts/ink_cap.h b/lib/ts/ink_cap.h index a457737..e29acea 100644 --- a/lib/ts/ink_cap.h +++ b/lib/ts/ink_cap.h @@ -44,4 +44,51 @@ extern int EnableCoreFile( bool flag ///< New enable state. ); + + +#if TS_USE_POSIX_CAP +bool elevateFileAccess(bool); +#else +bool restoreRootPriv(uid_t *old_euid = NULL); +bool removeRootPriv(uid_t euid); +#endif + + +class ElevateAccess { +public: + ElevateAccess(const bool state): elevated(false), saved_uid(0) { + if (state == true) { + elevate(); + } + } + + void elevate() { +#if TS_USE_POSIX_CAP + elevateFileAccess(true); +#else + restoreRootPriv(&saved_uid); +#endif + elevated = true; + } + + void demote() { +#if TS_USE_POSIX_CAP + elevateFileAccess(false); +#else + removeRootPriv(saved_uid); +#endif + elevated = false; + } + + ~ElevateAccess() { + if (elevated == true) { + demote(); + } + } + +private: + bool elevated; + uid_t saved_uid; +}; + #endif http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fffb60ed/mgmt/LocalManager.cc ---------------------------------------------------------------------- diff --git a/mgmt/LocalManager.cc b/mgmt/LocalManager.cc index 7b2799b..b7feeca 100644 --- a/mgmt/LocalManager.cc +++ b/mgmt/LocalManager.cc @@ -29,6 +29,7 @@ #include "Compatability.h" #include "LocalManager.h" #include "MgmtSocket.h" +#include "ink_cap.h" #if TS_USE_POSIX_CAP #include <sys/capability.h> @@ -1084,70 +1085,6 @@ LocalManager::listenForProxy() return; } -#if TS_USE_POSIX_CAP -/** Control file access privileges to bypass DAC. - @parm state Use @c true to enable elevated privileges, - @c false to disable. - @return @c true if successful, @c false otherwise. - - @internal After some pondering I decided that the file access - privilege was worth the effort of restricting. Unlike the network - privileges this can protect a host system from programming errors - by not (usually) permitting such errors to access arbitrary - files. This is particularly true since none of the config files - current enable this feature so it's not actually called. Still, - best to program defensively and have it available. - */ -bool -elevateFileAccess(bool state) -{ - bool zret = false; // return value. - cap_t cap_state = cap_get_proc(); // current capabilities - // Make a list of the capabilities we changed. - cap_value_t cap_list[] = { CAP_DAC_OVERRIDE }; - static int const CAP_COUNT = sizeof(cap_list)/sizeof(*cap_list); - - cap_set_flag(cap_state, CAP_EFFECTIVE, CAP_COUNT, cap_list, state ? CAP_SET : CAP_CLEAR); - zret = (0 == cap_set_proc(cap_state)); - cap_free(cap_state); - return zret; -} -#else -// bool removeRootPriv() -// -// - Returns true on success -// and false on failure -bool -removeRootPriv(uid_t euid) -{ - if (seteuid(euid) < 0) { - Debug("lm", "[removeRootPriv] seteuid failed : %s\n", strerror(errno)); - return false; - } - - Debug("lm", "[removeRootPriv] removed root privileges. Euid is %d\n", euid); - return true; -} - -// bool restoreRootPriv() -// -// - Returns true on success -// and false on failure -bool -restoreRootPriv(uid_t *old_euid) -{ - if (old_euid) - *old_euid = geteuid(); - if (seteuid(0) < 0) { - Debug("lm", "[restoreRootPriv] seteuid root failed : %s\n", strerror(errno)); - return false; - } - - Debug("lm", "[restoreRootPriv] restored root privileges. Euid is %d\n", 0); - - return true; -} -#endif /* * bindProxyPort() http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fffb60ed/mgmt/LocalManager.h ---------------------------------------------------------------------- diff --git a/mgmt/LocalManager.h b/mgmt/LocalManager.h index 7b677d8..9ea4158 100644 --- a/mgmt/LocalManager.h +++ b/mgmt/LocalManager.h @@ -159,11 +159,5 @@ private: extern LocalManager *lmgmt; -#if TS_USE_POSIX_CAP -bool elevateFileAccess(bool); -#else -bool restoreRootPriv(uid_t *old_euid = NULL); -bool removeRootPriv(uid_t euid); -#endif #endif /* _LOCAL_MANAGER_H */ http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fffb60ed/mgmt/RecordsConfig.cc ---------------------------------------------------------------------- diff --git a/mgmt/RecordsConfig.cc b/mgmt/RecordsConfig.cc index 4a73f19..647174f 100644 --- a/mgmt/RecordsConfig.cc +++ b/mgmt/RecordsConfig.cc @@ -1340,6 +1340,9 @@ RecordElement RecordsConfig[] = { , {RECT_CONFIG, "proxy.config.plugin.plugin_mgmt_dir", RECD_STRING, TS_BUILD_SYSCONFDIR "/plugins_mgmt", RECU_NULL, RR_NULL, RECC_NULL, NULL, RECA_NULL} , + {RECT_CONFIG, "proxy.config.plugin.load_elevated", RECD_INT, "0", RECU_NULL, RR_NULL, RECC_NULL, "[0-1]", RECA_NULL} + , + //############################################################################## //# http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fffb60ed/mgmt/Rollback.cc ---------------------------------------------------------------------- diff --git a/mgmt/Rollback.cc b/mgmt/Rollback.cc index e27a745..0399523 100644 --- a/mgmt/Rollback.cc +++ b/mgmt/Rollback.cc @@ -29,7 +29,7 @@ #include "MgmtUtils.h" #include "ExpandingArray.h" #include "MgmtSocket.h" - +#include "ink_cap.h" #define MAX_VERSION_DIGITS 11 #define DEFAULT_BACKUPS 2 http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fffb60ed/proxy/Plugin.cc ---------------------------------------------------------------------- diff --git a/proxy/Plugin.cc b/proxy/Plugin.cc index 1908199..5b2b19e 100644 --- a/proxy/Plugin.cc +++ b/proxy/Plugin.cc @@ -35,6 +35,7 @@ #include "InkAPIInternal.h" #include "Main.h" #include "Plugin.h" +#include "ink_cap.h" // HPUX: // LD_SHAREDCMD=ld -b @@ -136,7 +137,14 @@ plugin_load(int argc, char *argv[]) abort(); } - init(argc, argv); + // elevate the access to read files as root if compiled with capabilities, if not + // change the effective user to root + { + uint32_t elevate_access = 0; + REC_ReadConfigInteger(elevate_access, "proxy.config.plugin.load_elevated"); + ElevateAccess access(elevate_access != 0); + init(argc, argv); + } // done elevating access plugin_reg_list.push(plugin_reg_current); plugin_reg_current = NULL; http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fffb60ed/proxy/http/remap/UrlMapping.cc ---------------------------------------------------------------------- diff --git a/proxy/http/remap/UrlMapping.cc b/proxy/http/remap/UrlMapping.cc index c96b9b5..d5b00d1 100644 --- a/proxy/http/remap/UrlMapping.cc +++ b/proxy/http/remap/UrlMapping.cc @@ -23,7 +23,8 @@ #include "ink_defs.h" #include "UrlMapping.h" - +#include "I_RecCore.h" +#include "ink_cap.h" /** * **/ @@ -77,8 +78,14 @@ url_mapping::delete_instance(unsigned int index) void *ih = get_instance(index); remap_plugin_info* p = get_plugin(index); - if (ih && p && p->fp_tsremap_delete_instance) + if (ih && p && p->fp_tsremap_delete_instance) { + // elevate the access to read files as root if compiled with capabilities, if not + // change the effective user to root + uint32_t elevate_access = 0; + REC_ReadConfigInteger(elevate_access, "proxy.config.plugin.load_elevated"); + ElevateAccess access(elevate_access != 0); p->fp_tsremap_delete_instance(ih); + } // done elevating access } http://git-wip-us.apache.org/repos/asf/trafficserver/blob/fffb60ed/proxy/http/remap/UrlRewrite.cc ---------------------------------------------------------------------- diff --git a/proxy/http/remap/UrlRewrite.cc b/proxy/http/remap/UrlRewrite.cc index 8b51897..f88df84 100644 --- a/proxy/http/remap/UrlRewrite.cc +++ b/proxy/http/remap/UrlRewrite.cc @@ -34,6 +34,7 @@ #include "UrlMappingPathIndex.h" #include "ink_string.h" +#include "ink_cap.h" unsigned long @@ -1699,10 +1700,18 @@ UrlRewrite::load_remap_plugin(char *argv[], int argc, url_mapping *mp, char *err ri.size = sizeof(ri); ri.tsremap_version = TSREMAP_VERSION; - if (pi->fp_tsremap_init(&ri, tmpbuf, sizeof(tmpbuf) - 1) != TS_SUCCESS) { - Warning("Failed to initialize plugin %s (non-zero retval) ... bailing out", pi->path); - return -5; - } + // elevate the access to read files as root if compiled with capabilities, if not + // change the effective user to root + { + uint32_t elevate_access = 0; + REC_ReadConfigInteger(elevate_access, "proxy.config.plugin.load_elevated"); + ElevateAccess access(elevate_access != 0); + + if (pi->fp_tsremap_init(&ri, tmpbuf, sizeof(tmpbuf) - 1) != TS_SUCCESS) { + Warning("Failed to initialize plugin %s (non-zero retval) ... bailing out", pi->path); + return -5; + } + } // done elevating access Debug("remap_plugin", "Remap plugin \"%s\" - initialization completed", c); } @@ -1756,7 +1765,16 @@ UrlRewrite::load_remap_plugin(char *argv[], int argc, url_mapping *mp, char *err void* ih; Debug("remap_plugin", "creating new plugin instance"); - TSReturnCode res = pi->fp_tsremap_new_instance(parc, parv, &ih, tmpbuf, sizeof(tmpbuf) - 1); + + TSReturnCode res = TS_ERROR; + // elevate the access to read files as root if compiled with capabilities, if not + // change the effective user to root + { + uint32_t elevate_access = 0; + REC_ReadConfigInteger(elevate_access, "proxy.config.plugin.load_elevated"); + ElevateAccess access(elevate_access != 0); + res = pi->fp_tsremap_new_instance(parc, parv, &ih, tmpbuf, sizeof(tmpbuf) - 1); + } // done elevating access Debug("remap_plugin", "done creating new plugin instance");
