Opened 2 months ago

Last modified 2 months ago

#1521 new defect

Enable open_file_cache may cause index module return 403 forbidden

Reported by: cangmingh@… Owned by:
Priority: minor Milestone:
Component: nginx-module Version: 1.10.x
Keywords: open_file_cache, index module Cc:
uname -a: Linux weichinh-Linux 4.10.0-38-generic #42~16.04.1-Ubuntu SMP Tue Oct 10 16:32:20 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
nginx -V: nginx version: nginx/1.10.3 (Ubuntu) built with OpenSSL 1.0.2g 1 Mar 2016 TLS SNI support enabled configure arguments: --with-cc-opt='-g -O2 -fPIE -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/ --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_addition_module --with-http_dav_module --with-http_geoip_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module --with-http_v2_module --with-http_sub_module --with-http_xslt_module --with-stream --with-stream_ssl_module --with-mail --with-mail_ssl_module --with-threads


After enable open_file_cache, Nginx index module will return 403 forbidden directly for those index file which cannot be read by Nginx.
It will not happen when open_file_cache is disable, since Nginx do not need to read these file. Nginx just pass the file path to the right upstream when it can stat the file. What it needed is only the read permission of the index file's directory but not the index file's.

The reproduce steps:

  1. Let nginx worker run as user http
  2. Let php-fpm run as user php
  3. Create a index.php under document root which can only read by php, but not http
  4. Enable open_file_cache, curl localhost, then you will find it return 403
  5. Disable open_file_cache, curl localhost, then you will find it work perfect

After tracing the ngx_http_index_module.c, I think the problem is when open_file_cache disable, the function, ngx_open_cached_file (ngx_http_index_module.c line 217), will only stat the file. But after open_file_cache enable, ngx_open_cached_file will try to open the file to get fd. Then it gets the NGX_EACCES.

The workarround solution maybe call ngx_open_cached_file again with ngx_open_cached_file(NULL, &path, &of, r->pool) after getting NGX_EACCES by first call.

By the way, this problem also happen in nginx 1.13.9

Change History (1)

comment:1 Changed 2 months ago by mdounin

Indeed, open file cache, even if only stat()'ing a file is needed, will try to open the file instead and will only stat it after opening. This is done to save resources in a typical scenario when nginx needs to check if the file exists, and then opens it and returns to the user. With the current approach, it only needs open() + fstat() instead of stat() + open() + fstat() with traditional approach. This also simplifies the code.

This approach indeed can cause incorrect EACCESS errors when nginx has enough rights to stat() a file, but not enough rights to read it, as in the configuration described.

Falling back to an uncached ngx_open_cached_file() looks like a bad idea though. The purpose of open file cache is to cache file access results, and doing additional uncached call will defeat the idea.

Switching off open_file_cache might be a better solutions for such configurations.

Note: See TracTickets for help on using tickets.