[PATCH] Add client_body_temp_access configuration directive

Paul paul at mrarm.io
Mon Oct 15 18:14:56 UTC 2018


Hello and thank you for the code review,

On 2018-10-15 16:27, Maxim Dounin wrote:
> Hello!
> 
> On Fri, Oct 12, 2018 at 09:54:04PM +0200, Paul Pawlowski via 
> nginx-devel wrote:
> 
>> # HG changeset patch
>> # User Paul Pawlowski <paul at mrarm.io>
>> # Date 1539371172 -7200
>> #      Fri Oct 12 21:06:12 2018 +0200
>> # Node ID 67cc676dbfaf56332bb6c61e635c0073c1e49907
>> # Parent  8b68d50090e4f134a35da60146fefd5e63770759
>> Add client_body_temp_access configuration directive
> 
> Style: there should be a trailing dot and a reference to ticket
> you've created, and please use past tense.  Also, I think that
> "client_body_access" might be a better name:
> 
> Added client_body_access directive (ticket #1653).
> 
>> Adds client_body_temp_access configuration directive, which sets the 
>> unix permissions of the temporary files holding client request bodies.
>> 
>> This makes it possible for a process running as another user to access 
>> the files stored using client_body_temp_path and 
>> client_body_in_file_only.
>> This is useful when using the mentioned directives in order to have 
>> nginx store the request body to file and forward the file path to 
>> another server running on the same machine as another user.
> 
> Style: please wrap lines at 80 characters or less.
> 
I've addressed the style concerns, as well as changed the name to the 
suggested one.
>> 
>> diff -r 8b68d50090e4 -r 67cc676dbfaf contrib/vim/syntax/nginx.vim
>> --- a/contrib/vim/syntax/nginx.vim	Wed Oct 03 14:08:51 2018 +0300
>> +++ b/contrib/vim/syntax/nginx.vim	Fri Oct 12 21:06:12 2018 +0200
>> @@ -155,6 +155,7 @@
>>  syn keyword ngxDirective contained chunked_transfer_encoding
>>  syn keyword ngxDirective contained client_body_buffer_size
>>  syn keyword ngxDirective contained client_body_in_file_only
>> +syn keyword ngxDirective contained client_body_temp_access
>>  syn keyword ngxDirective contained client_body_in_single_buffer
>>  syn keyword ngxDirective contained client_body_temp_path
>>  syn keyword ngxDirective contained client_body_timeout
> 
> This list is expected to be sorted alphabetically.
> 
>> diff -r 8b68d50090e4 -r 67cc676dbfaf src/http/ngx_http_core_module.c
>> --- a/src/http/ngx_http_core_module.c	Wed Oct 03 14:08:51 2018 +0300
>> +++ b/src/http/ngx_http_core_module.c	Fri Oct 12 21:06:12 2018 +0200
>> @@ -370,6 +370,13 @@
>>        offsetof(ngx_http_core_loc_conf_t, client_body_temp_path),
>>        NULL },
>> 
>> +    { ngx_string("client_body_temp_access"),
>> +      
>> NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
>> +      ngx_conf_set_access_slot,
>> +      NGX_HTTP_LOC_CONF_OFFSET,
>> +      offsetof(ngx_http_core_loc_conf_t, client_body_temp_access),
>> +      NULL },
>> +
>>      { ngx_string("client_body_in_file_only"),
>>        
>> NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
>>        ngx_conf_set_enum_slot,
>> @@ -3373,6 +3380,7 @@
>>      clcf->if_modified_since = NGX_CONF_UNSET_UINT;
>>      clcf->max_ranges = NGX_CONF_UNSET_UINT;
>>      clcf->client_body_in_file_only = NGX_CONF_UNSET_UINT;
>> +    clcf->client_body_temp_access = NGX_CONF_UNSET_UINT;
>>      clcf->client_body_in_single_buffer = NGX_CONF_UNSET;
>>      clcf->internal = NGX_CONF_UNSET;
>>      clcf->sendfile = NGX_CONF_UNSET;
>> @@ -3594,6 +3602,8 @@
>>      ngx_conf_merge_uint_value(conf->client_body_in_file_only,
>>                                prev->client_body_in_file_only,
>>                                NGX_HTTP_REQUEST_BODY_FILE_OFF);
>> +    ngx_conf_merge_uint_value(conf->client_body_temp_access,
>> +                              prev->client_body_temp_access, 0);
> 
> Explicitly using 0600 as the default should be a better option.
I have changed the default value to 0600.
> 
>>      ngx_conf_merge_value(conf->client_body_in_single_buffer,
>>                                prev->client_body_in_single_buffer, 0);
>>      ngx_conf_merge_value(conf->internal, prev->internal, 0);
>> diff -r 8b68d50090e4 -r 67cc676dbfaf src/http/ngx_http_core_module.h
>> --- a/src/http/ngx_http_core_module.h	Wed Oct 03 14:08:51 2018 +0300
>> +++ b/src/http/ngx_http_core_module.h	Fri Oct 12 21:06:12 2018 +0200
>> @@ -375,6 +375,7 @@
>>      ngx_uint_t    if_modified_since;       /* if_modified_since */
>>      ngx_uint_t    max_ranges;              /* max_ranges */
>>      ngx_uint_t    client_body_in_file_only; /* 
>> client_body_in_file_only */
>> +    ngx_uint_t    client_body_temp_access; /* client_body_temp_access 
>> */
>> 
>>      ngx_flag_t    client_body_in_single_buffer;
>>                                             /* 
>> client_body_in_singe_buffer */
>> diff -r 8b68d50090e4 -r 67cc676dbfaf src/http/ngx_http_request_body.c
>> --- a/src/http/ngx_http_request_body.c	Wed Oct 03 14:08:51 2018 +0300
>> +++ b/src/http/ngx_http_request_body.c	Fri Oct 12 21:06:12 2018 +0200
>> @@ -450,6 +450,7 @@
>>          tf->file.fd = NGX_INVALID_FILE;
>>          tf->file.log = r->connection->log;
>>          tf->path = clcf->client_body_temp_path;
>> +        tf->access = clcf->client_body_temp_access;
>>          tf->pool = r->pool;
>>          tf->warn = "a client request body is buffered to a temporary 
>> file";
>>          tf->log_level = r->request_body_file_log_level;
> 
> The following block:
> 
>         if (r->request_body_file_group_access) {
>             tf->access = 0660;
>         }
> 
> raises the question on how it is expected to interact with
> r->request_body_file_group_access.  I suspect that
> r->request_body_file_group_access is not currently needed and can
> be removed altogether, but this needs an additional investigation.
I've checked where is it used - the only place is the
ngx_http_dav_module, where it is used in order to set the permissions
for the temporary uploaded file in the PUT handler - however, as the
file is later moved for storage using ngx_ext_rename_file function (in
ngx_http_dav_put_handler) with permissions taken from the configuration
file (with a default value of 0600) I do not believe that the temporary
file permission matter at that stage.

The usage by third party modules also seem limited:
I've tried to do a GitHub search for it:
https://github.com/search?q=request_body_file_group_access+-filename%3Angx_http_request_body.c+-filename%3Angx_http_request.h+-filename%3Angx_http_dav_module.c&type=Code
which results in 1,123 code results. However most of these are simply
slightly altered versions of ngx_http_request_body.c, and if we exclude
the top three results we end up with 264 results:
https://github.com/search?q=request_body_file_group_access+-filename%3Angx_http_request_body.c+-filename%3Angx_http_request.h+-filename%3Angx_http_dav_module.c+-filename%3Angx_http_lua_req_body.c+-filename%3Angx_http_waf_filter_module.c+-filename%3Angx_http_spdy.c&type=Code
with most of them still largely being nginx codebase - however a few
usages can still be found including:
- 
https://github.com/oscar810429/graphicsmagick_nginx_module/blob/6f171579ba7638f62f885d3d8e0687d7977f2f33/ngx_http_graphicsmagick_module.c 
[I don't believe it is needed here - the file is not forwarded to other 
users I believe after taking a quick look at the code]
- 
https://github.com/heapsource/BlackLinks/blob/8173ba44270d65cbe50aa2865eab91af3d44f3d4/nginx-hello/ngx_http_hello_world_module.c
- 
https://github.com/alacner/nginx_lua_module/blob/e194c26f96e50504540fd5830283e1c01670d170/src/ngx_http_lua_module.c
- 
https://github.com/AntonRiab/ngx_pgcopy/blob/ca32432024d0677754faddbe4d8b45c5d896c79b/ngx_http_pgcopy_module.c
Even though I believe they should be replaceable, is this something
I should look into more?

I'm making the deletion of the request_body_file_group_access a separate
commit, as this touches code not directly related to the core added
functionality.
> 
> Another question to consider is how this is expected to interact
> with directories created for various temp file levels.  These
> directories, much like the client_body_temp_path diretory itself,
> are unconditionally created with 0700 access, and will prevent
> access to temporary files from non-nginx user as well.  These can
> be pre-created with appropriate permissions - but as long as it is
> a recommended approach, this probably needs to be mentioned in the
> commit log.
This is an issue I have completely missed while writing this patch.
I have checked how do the other nginx module solve this particular
issue and figured out that probably the best option would be to use
the specified file permissions as the ones to use (using the
ngx_dir_access helper function), and this is what I've implemented.




I'm unfortunately unsure what is the proper way to E-Mail the patches in
a response mail so I'm simply attaching them to the E-Mail below
(there are two separate commits below):

# HG changeset patch
# User Paul Pawlowski <paul at mrarm.io>
# Date 1539621300 -7200
#      Mon Oct 15 18:35:00 2018 +0200
# Node ID c94787463c982dab370b695e2f3ddcbc7655ead5
# Parent  8b68d50090e4f134a35da60146fefd5e63770759
Added client_body_access configuration directive (ticket #1651).

Added client_body_access configuration directive, which sets the unix
permissions of the temporary files and directories holding client 
request
bodies.

This makes it possible for a process running as another user to access
the files stored using client_body_temp_path and 
client_body_in_file_only.
This is useful when using the mentioned directives in order to have 
nginx store
the request body to file and forward the file path to another server 
running on
the same machine as another user.

diff -r 8b68d50090e4 -r c94787463c98 contrib/vim/syntax/nginx.vim
--- a/contrib/vim/syntax/nginx.vim      Wed Oct 03 14:08:51 2018 +0300
+++ b/contrib/vim/syntax/nginx.vim      Mon Oct 15 18:35:00 2018 +0200
@@ -153,6 +153,7 @@
  syn keyword ngxDirective contained charset
  syn keyword ngxDirective contained charset_types
  syn keyword ngxDirective contained chunked_transfer_encoding
+syn keyword ngxDirective contained client_body_access
  syn keyword ngxDirective contained client_body_buffer_size
  syn keyword ngxDirective contained client_body_in_file_only
  syn keyword ngxDirective contained client_body_in_single_buffer
diff -r 8b68d50090e4 -r c94787463c98 src/core/ngx_file.c
--- a/src/core/ngx_file.c       Wed Oct 03 14:08:51 2018 +0300
+++ b/src/core/ngx_file.c       Mon Oct 15 18:35:00 2018 +0200
@@ -146,10 +146,17 @@
      uint32_t                  n;
      ngx_err_t                 err;
      ngx_str_t                 name;
+    ngx_uint_t                path_access;
      ngx_uint_t                prefix;
      ngx_pool_cleanup_t       *cln;
      ngx_pool_cleanup_file_t  *clnf;

+    if (access != 0) {
+        path_access = ngx_dir_access(access);
+    } else {
+        path_access = 0700;
+    }
+
      if (file->name.len) {
          name = file->name;
          levels = 0;
@@ -230,7 +237,7 @@
              return NGX_ERROR;
          }

-        if (ngx_create_path(file, path) == NGX_ERROR) {
+        if (ngx_create_path(file, path, path_access) == NGX_ERROR) {
              return NGX_ERROR;
          }
      }
@@ -263,7 +270,7 @@


  ngx_int_t
-ngx_create_path(ngx_file_t *file, ngx_path_t *path)
+ngx_create_path(ngx_file_t *file, ngx_path_t *path, ngx_uint_t access)
  {
      size_t      pos;
      ngx_err_t   err;
@@ -283,7 +290,7 @@
          ngx_log_debug1(NGX_LOG_DEBUG_CORE, file->log, 0,
                         "temp file: \"%s\"", file->name.data);

-        if (ngx_create_dir(file->name.data, 0700) == NGX_FILE_ERROR) {
+        if (ngx_create_dir(file->name.data, access) == NGX_FILE_ERROR) 
{
              err = ngx_errno;
              if (err != NGX_EEXIST) {
                  ngx_log_error(NGX_LOG_CRIT, file->log, err,
diff -r 8b68d50090e4 -r c94787463c98 src/core/ngx_file.h
--- a/src/core/ngx_file.h       Wed Oct 03 14:08:51 2018 +0300
+++ b/src/core/ngx_file.h       Mon Oct 15 18:35:00 2018 +0200
@@ -140,7 +140,8 @@
      ngx_pool_t *pool, ngx_uint_t persistent, ngx_uint_t clean,
      ngx_uint_t access);
  void ngx_create_hashed_filename(ngx_path_t *path, u_char *file, size_t 
len);
-ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path);
+ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path,
+    ngx_uint_t access);
  ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access);
  ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot);
  ngx_int_t ngx_create_paths(ngx_cycle_t *cycle, ngx_uid_t user);
diff -r 8b68d50090e4 -r c94787463c98 src/http/ngx_http_core_module.c
--- a/src/http/ngx_http_core_module.c   Wed Oct 03 14:08:51 2018 +0300
+++ b/src/http/ngx_http_core_module.c   Mon Oct 15 18:35:00 2018 +0200
@@ -370,6 +370,13 @@
        offsetof(ngx_http_core_loc_conf_t, client_body_temp_path),
        NULL },

+    { ngx_string("client_body_access"),
+      
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
+      ngx_conf_set_access_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, client_body_access),
+      NULL },
+
      { ngx_string("client_body_in_file_only"),
        
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
        ngx_conf_set_enum_slot,
@@ -3373,6 +3380,7 @@
      clcf->if_modified_since = NGX_CONF_UNSET_UINT;
      clcf->max_ranges = NGX_CONF_UNSET_UINT;
      clcf->client_body_in_file_only = NGX_CONF_UNSET_UINT;
+    clcf->client_body_access = NGX_CONF_UNSET_UINT;
      clcf->client_body_in_single_buffer = NGX_CONF_UNSET;
      clcf->internal = NGX_CONF_UNSET;
      clcf->sendfile = NGX_CONF_UNSET;
@@ -3594,6 +3602,8 @@
      ngx_conf_merge_uint_value(conf->client_body_in_file_only,
                                prev->client_body_in_file_only,
                                NGX_HTTP_REQUEST_BODY_FILE_OFF);
+    ngx_conf_merge_uint_value(conf->client_body_access,
+                              prev->client_body_access, 0600);
      ngx_conf_merge_value(conf->client_body_in_single_buffer,
                                prev->client_body_in_single_buffer, 0);
      ngx_conf_merge_value(conf->internal, prev->internal, 0);
diff -r 8b68d50090e4 -r c94787463c98 src/http/ngx_http_core_module.h
--- a/src/http/ngx_http_core_module.h   Wed Oct 03 14:08:51 2018 +0300
+++ b/src/http/ngx_http_core_module.h   Mon Oct 15 18:35:00 2018 +0200
@@ -375,6 +375,7 @@
      ngx_uint_t    if_modified_since;       /* if_modified_since */
      ngx_uint_t    max_ranges;              /* max_ranges */
      ngx_uint_t    client_body_in_file_only; /* client_body_in_file_only 
*/
+    ngx_uint_t    client_body_access;      /* client_body_access */

      ngx_flag_t    client_body_in_single_buffer;
                                             /* 
client_body_in_singe_buffer */
diff -r 8b68d50090e4 -r c94787463c98 src/http/ngx_http_request_body.c
--- a/src/http/ngx_http_request_body.c  Wed Oct 03 14:08:51 2018 +0300
+++ b/src/http/ngx_http_request_body.c  Mon Oct 15 18:35:00 2018 +0200
@@ -450,6 +450,7 @@
          tf->file.fd = NGX_INVALID_FILE;
          tf->file.log = r->connection->log;
          tf->path = clcf->client_body_temp_path;
+        tf->access = clcf->client_body_access;
          tf->pool = r->pool;
          tf->warn = "a client request body is buffered to a temporary 
file";
          tf->log_level = r->request_body_file_log_level;






# HG changeset patch
# User Paul Pawlowski <paul at mrarm.io>
# Date 1539623192 -7200
#      Mon Oct 15 19:06:32 2018 +0200
# Node ID e6f5c3e20646abe8708db185e5acdd861c13ce35
# Parent  c94787463c982dab370b695e2f3ddcbc7655ead5
Removed request_body_file_group_access from ngx_http_request_s.

request_body_file_group_access's only usage is in the 
ngx_http_dav_module.
However the temporary file created by that module after a successful 
upload is
moved into another directory, and the file permissions are changed to 
user
specified ones. Therefore, it doesn't matter what the initial file 
permissions
were and the code can be simplified.

diff -r c94787463c98 -r e6f5c3e20646 
src/http/modules/ngx_http_dav_module.c
--- a/src/http/modules/ngx_http_dav_module.c    Mon Oct 15 18:35:00 2018 
+0200
+++ b/src/http/modules/ngx_http_dav_module.c    Mon Oct 15 19:06:32 2018 
+0200
@@ -170,7 +170,6 @@
          r->request_body_in_file_only = 1;
          r->request_body_in_persistent_file = 1;
          r->request_body_in_clean_file = 1;
-        r->request_body_file_group_access = 1;
          r->request_body_file_log_level = 0;

          rc = ngx_http_read_client_request_body(r, 
ngx_http_dav_put_handler);
diff -r c94787463c98 -r e6f5c3e20646 src/http/ngx_http_request.h
--- a/src/http/ngx_http_request.h       Mon Oct 15 18:35:00 2018 +0200
+++ b/src/http/ngx_http_request.h       Mon Oct 15 19:06:32 2018 +0200
@@ -482,7 +482,6 @@
      unsigned                          request_body_in_file_only:1;
      unsigned                          
request_body_in_persistent_file:1;
      unsigned                          request_body_in_clean_file:1;
-    unsigned                          request_body_file_group_access:1;
      unsigned                          request_body_file_log_level:3;
      unsigned                          request_body_no_buffering:1;

diff -r c94787463c98 -r e6f5c3e20646 src/http/ngx_http_request_body.c
--- a/src/http/ngx_http_request_body.c  Mon Oct 15 18:35:00 2018 +0200
+++ b/src/http/ngx_http_request_body.c  Mon Oct 15 19:06:32 2018 +0200
@@ -457,10 +457,6 @@
          tf->persistent = r->request_body_in_persistent_file;
          tf->clean = r->request_body_in_clean_file;

-        if (r->request_body_file_group_access) {
-            tf->access = 0660;
-        }
-
          rb->temp_file = tf;

          if (rb->bufs == NULL) {


More information about the nginx-devel mailing list