diff --git a/auto/os/linux b/auto/os/linux index a0c8795bb..e4aa0e549 100644 --- a/auto/os/linux +++ b/auto/os/linux @@ -157,6 +157,37 @@ ngx_feature_test="if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) return 1" . 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 " +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 " +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()" diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h index 2b48ccbd6..a825da2f9 100644 --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -114,6 +114,8 @@ typedef struct { ngx_array_t env; char **environment; + + ngx_uint_t transparent; /* unsigned transparent:1; */ } ngx_core_conf_t; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 6d0f4ee52..f8d5707d3 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -6078,6 +6078,12 @@ ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, 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, diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h index 2f6129d88..b22ea4378 100644 --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -99,6 +99,11 @@ typedef struct iocb ngx_aiocb_t; #endif +#if (NGX_HAVE_CAPABILITIES) +#include +#endif + + #define NGX_LISTEN_BACKLOG 511 diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c index a20a515c7..40654b3a2 100644 --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -839,12 +839,44 @@ ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker) 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) { diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c index ad81cc8b7..818d7329b 100644 --- a/src/stream/ngx_stream_proxy_module.c +++ b/src/stream/ngx_stream_proxy_module.c @@ -2155,6 +2155,12 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 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,