Mercurial > hg > nginx
changeset 7174:84e53e4735a4
Retain CAP_NET_RAW capability for transparent proxying.
The capability is retained automatically in unprivileged worker processes after
changing UID if transparent proxying is enabled at least once in nginx
configuration.
The feature is only available in Linux.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Wed, 13 Dec 2017 20:40:53 +0300 |
parents | 057adb2a9d23 |
children | 56923e8e01a5 |
files | auto/os/linux src/core/ngx_cycle.h src/http/ngx_http_upstream.c src/os/unix/ngx_linux_config.h src/os/unix/ngx_process_cycle.c src/stream/ngx_stream_proxy_module.c |
diffstat | 6 files changed, 82 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/auto/os/linux Mon Dec 11 16:28:11 2017 +0000 +++ b/auto/os/linux Wed Dec 13 20:40:53 2017 +0300 @@ -157,6 +157,37 @@ . auto/feature +# prctl(PR_SET_KEEPCAPS) + +ngx_feature="prctl(PR_SET_KEEPCAPS)" +ngx_feature_name="NGX_HAVE_PR_SET_KEEPCAPS" +ngx_feature_run=yes +ngx_feature_incs="#include <sys/prctl.h>" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) return 1" +. auto/feature + + +# capabilities + +ngx_feature="capabilities" +ngx_feature_name="NGX_HAVE_CAPABILITIES" +ngx_feature_run=no +ngx_feature_incs="#include <sys/capability.h>" +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct __user_cap_data_struct data; + struct __user_cap_header_struct header; + + header.version = _LINUX_CAPABILITY_VERSION_3; + data.effective = CAP_TO_MASK(CAP_NET_RAW); + data.permitted = 0; + + (void) capset(&header, &data)" +. auto/feature + + # crypt_r() ngx_feature="crypt_r()"
--- a/src/core/ngx_cycle.h Mon Dec 11 16:28:11 2017 +0000 +++ b/src/core/ngx_cycle.h Wed Dec 13 20:40:53 2017 +0300 @@ -114,6 +114,8 @@ ngx_array_t env; char **environment; + + ngx_uint_t transparent; /* unsigned transparent:1; */ } ngx_core_conf_t;
--- a/src/http/ngx_http_upstream.c Mon Dec 11 16:28:11 2017 +0000 +++ b/src/http/ngx_http_upstream.c Wed Dec 13 20:40:53 2017 +0300 @@ -6078,6 +6078,12 @@ if (cf->args->nelts > 2) { if (ngx_strcmp(value[2].data, "transparent") == 0) { #if (NGX_HAVE_TRANSPARENT_PROXY) + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(cf->cycle->conf_ctx, + ngx_core_module); + + ccf->transparent = 1; local->transparent = 1; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
--- a/src/os/unix/ngx_linux_config.h Mon Dec 11 16:28:11 2017 +0000 +++ b/src/os/unix/ngx_linux_config.h Wed Dec 13 20:40:53 2017 +0300 @@ -99,6 +99,11 @@ #endif +#if (NGX_HAVE_CAPABILITIES) +#include <sys/capability.h> +#endif + + #define NGX_LISTEN_BACKLOG 511
--- a/src/os/unix/ngx_process_cycle.c Mon Dec 11 16:28:11 2017 +0000 +++ b/src/os/unix/ngx_process_cycle.c Wed Dec 13 20:40:53 2017 +0300 @@ -839,12 +839,44 @@ ccf->username, ccf->group); } +#if (NGX_HAVE_PR_SET_KEEPCAPS && NGX_HAVE_CAPABILITIES) + if (ccf->transparent && ccf->user) { + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "prctl(PR_SET_KEEPCAPS, 1) failed"); + /* fatal */ + exit(2); + } + } +#endif + if (setuid(ccf->user) == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, "setuid(%d) failed", ccf->user); /* fatal */ exit(2); } + +#if (NGX_HAVE_CAPABILITIES) + if (ccf->transparent && ccf->user) { + struct __user_cap_data_struct data; + struct __user_cap_header_struct header; + + ngx_memzero(&header, sizeof(struct __user_cap_header_struct)); + ngx_memzero(&data, sizeof(struct __user_cap_data_struct)); + + header.version = _LINUX_CAPABILITY_VERSION_3; + data.effective = CAP_TO_MASK(CAP_NET_RAW); + data.permitted = data.effective; + + if (capset(&header, &data) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, + "capset() failed"); + /* fatal */ + exit(2); + } + } +#endif } if (worker >= 0) {
--- a/src/stream/ngx_stream_proxy_module.c Mon Dec 11 16:28:11 2017 +0000 +++ b/src/stream/ngx_stream_proxy_module.c Wed Dec 13 20:40:53 2017 +0300 @@ -2155,6 +2155,12 @@ if (cf->args->nelts > 2) { if (ngx_strcmp(value[2].data, "transparent") == 0) { #if (NGX_HAVE_TRANSPARENT_PROXY) + ngx_core_conf_t *ccf; + + ccf = (ngx_core_conf_t *) ngx_get_conf(cf->cycle->conf_ctx, + ngx_core_module); + + ccf->transparent = 1; local->transparent = 1; #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,