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.
This commit is contained in:
Roman Arutyunyan committed 2017-12-13 20:40:53 +03:00
1 parent d2d737e70b
commit 752f66bf7d
6 files changed
+82

No files matched your search

+31
View File
@@ -157,6 +157,37 @@ ngx_feature_test="if (prctl(PR_SET_DUMPABLE, 1, 0, 0, 0) == -1) return 1"
. auto/feature . 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() # crypt_r()
ngx_feature="crypt_r()" ngx_feature="crypt_r()"
+2
View File
@@ -114,6 +114,8 @@ typedef struct {
ngx_array_t env; ngx_array_t env;
char **environment; char **environment;
ngx_uint_t transparent; /* unsigned transparent:1; */
} ngx_core_conf_t; } ngx_core_conf_t;
+6
View File
@@ -6078,6 +6078,12 @@ ngx_http_upstream_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
if (cf->args->nelts > 2) { if (cf->args->nelts > 2) {
if (ngx_strcmp(value[2].data, "transparent") == 0) { if (ngx_strcmp(value[2].data, "transparent") == 0) {
#if (NGX_HAVE_TRANSPARENT_PROXY) #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; local->transparent = 1;
#else #else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+5
View File
@@ -99,6 +99,11 @@ typedef struct iocb ngx_aiocb_t;
#endif #endif
#if (NGX_HAVE_CAPABILITIES)
#include <sys/capability.h>
#endif
#define NGX_LISTEN_BACKLOG 511 #define NGX_LISTEN_BACKLOG 511
+32
View File
@@ -839,12 +839,44 @@ ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
ccf->username, ccf->group); 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) { if (setuid(ccf->user) == -1) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
"setuid(%d) failed", ccf->user); "setuid(%d) failed", ccf->user);
/* fatal */ /* fatal */
exit(2); 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) { if (worker >= 0) {
+6
View File
@@ -2155,6 +2155,12 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (cf->args->nelts > 2) { if (cf->args->nelts > 2) {
if (ngx_strcmp(value[2].data, "transparent") == 0) { if (ngx_strcmp(value[2].data, "transparent") == 0) {
#if (NGX_HAVE_TRANSPARENT_PROXY) #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; local->transparent = 1;
#else #else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,