diff options
author | Roman Arutyunyan <arut@nginx.com> | 2017-12-13 20:40:53 +0300 |
---|---|---|
committer | Roman Arutyunyan <arut@nginx.com> | 2017-12-13 20:40:53 +0300 |
commit | 752f66bf7d70fae2bf05fbf5941ff4be52b2b9a5 (patch) | |
tree | 78fc3bcc2f52d8fc71fa4ec12080fdf891e0a113 /src/os | |
parent | d2d737e70b46429ef9ed71b99402a9151f3c2e1f (diff) |
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.
Diffstat (limited to 'src/os')
-rw-r--r-- | src/os/unix/ngx_linux_config.h | 5 | ||||
-rw-r--r-- | src/os/unix/ngx_process_cycle.c | 32 |
2 files changed, 37 insertions, 0 deletions
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 <sys/capability.h> +#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) { |