[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