[nginx] Retain CAP_NET_RAW capability for transparent proxying.
Roman Arutyunyan
arut at nginx.com
Wed Dec 13 18:12:27 UTC 2017
details: http://hg.nginx.org/nginx/rev/84e53e4735a4
branches:
changeset: 7174:84e53e4735a4
user: Roman Arutyunyan <arut at nginx.com>
date: Wed Dec 13 20:40:53 2017 +0300
description:
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:
auto/os/linux | 31 +++++++++++++++++++++++++++++++
src/core/ngx_cycle.h | 2 ++
src/http/ngx_http_upstream.c | 6 ++++++
src/os/unix/ngx_linux_config.h | 5 +++++
src/os/unix/ngx_process_cycle.c | 32 ++++++++++++++++++++++++++++++++
src/stream/ngx_stream_proxy_module.c | 6 ++++++
6 files changed, 82 insertions(+), 0 deletions(-)
diffs (148 lines):
diff -r 057adb2a9d23 -r 84e53e4735a4 auto/os/linux
--- 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 @@ ngx_feature_test="if (prctl(PR_SET_DUMPA
. 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()"
diff -r 057adb2a9d23 -r 84e53e4735a4 src/core/ngx_cycle.h
--- 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 @@ typedef struct {
ngx_array_t env;
char **environment;
+
+ ngx_uint_t transparent; /* unsigned transparent:1; */
} ngx_core_conf_t;
diff -r 057adb2a9d23 -r 84e53e4735a4 src/http/ngx_http_upstream.c
--- 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 @@ ngx_http_upstream_bind_set_slot(ngx_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,
diff -r 057adb2a9d23 -r 84e53e4735a4 src/os/unix/ngx_linux_config.h
--- 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 @@ typedef struct iocb ngx_aiocb_t;
#endif
+#if (NGX_HAVE_CAPABILITIES)
+#include <sys/capability.h>
+#endif
+
+
#define NGX_LISTEN_BACKLOG 511
diff -r 057adb2a9d23 -r 84e53e4735a4 src/os/unix/ngx_process_cycle.c
--- 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 @@ ngx_worker_process_init(ngx_cycle_t *cyc
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 -r 057adb2a9d23 -r 84e53e4735a4 src/stream/ngx_stream_proxy_module.c
--- 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 @@ ngx_stream_proxy_bind(ngx_conf_t *cf, ng
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,
More information about the nginx-devel
mailing list