php / php/php-src

Wrong value from ini_get() for shared files because of opcache optimization

Đang mở
#8,699 16 bình luận 1 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Bug Category: Engine Category: Optimizer Extension: opcache SAPI: fpm Status: Verified
Ngôn ngữ chính
C
Star
40.4k
Fork
8.2k
Merge trung bình
2 ngày 13 giờ
Pull request đã merge (30 ngày)
96

Mô tả

Description

Opcache saves values from ini_get() for PHP_INI_SYSTEM type directives in the opcache when optimization is enabled.
This is a problem when a shared file uses ini_get() for PHP_INI_SYSTEM.

Example of this is a server with multiple virtual hosts where the sites use a common/shared framework.
The framework has an image uploading part where it fetches the upload_tmp_dir setting from ini to use a place for temporary image manipulations.
The virtual hosts are set up using PHP_ADMIN_VALUE to set a specific upload folder for each site.

fastcgi_param PHP_ADMIN_VALUE "upload_tmp_dir=/tmp/uploads/site1";

In this scenario the framework uses ini_get('upload_tmp_dir') to get the tmp folder value, but the value it gets is always the value for the first site that included that php file. So if site "foo.example.com" was first, then ALL other sites will get the upload_tmp_dir from "foo.example.com".

I reproduced this in all versions >=7.2, and for cli, fpm and mod_php.

Security

Not sure this counts as a security problem but this means that information could leak between sites.

Note that using PHP_ADMIN_VALUE for any option results in this problem.

Ways to reproduce:
Setup php files
mkdir /tmp/test/ && cd /tmp/test/
echo '<?php echo "S: " . ini_get("upload_tmp_dir") . "\n";' > shared.php
echo '<?php echo "1: " . ini_get("upload_tmp_dir") . "\n"; include "./shared.php";' > 1.php
echo '<?php echo "2: " . ini_get("upload_tmp_dir") . "\n"; include "./shared.php";' > 2.php
Cli

Create a cli-opcache.ini file in the "scan" additional .ini files directory:

zend_extension=opcache.so
[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.file_cache="/tmp/php-file-cache"
opcache.file_cache_only=1
opcache.file_cache_consistency_checks=1

Create file cache folder

mkdir /tmp/php-file-cache

Run the test

php -d upload_tmp_dir=/tmp/num1 /tmp/test/1.php
php -d upload_tmp_dir=/tmp/num2 /tmp/test/2.php

Expected result:

1: /tmp/num1
S: /tmp/num1
2: /tmp/num2
S: /tmp/num2

Actual result:

1: /tmp/num1
S: /tmp/num1
2: /tmp/num2
S: /tmp/num1
nginx + fpm

Make sure that opcache with optimizations is enabled.

Setup two virtual hosts and reload nginx:

server {
    listen 80; 
    server_name p1; 
    root /tmp/test; 
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
	    fastcgi_pass   127.0.0.1:9000;
	    fastcgi_param  PHP_ADMIN_VALUE "upload_tmp_dir=/tmp/cache1";
    }
}
server {
    listen 80; 
    server_name p2; 
    root /tmp/test; 
    location ~ \.php$ {
	    include snippets/fastcgi-php.conf;
	    fastcgi_pass   127.0.0.1:9000;
	    fastcgi_param  PHP_ADMIN_VALUE "upload_tmp_dir=/tmp/cache2";
    }
}

Run the tests:

curl --resolve p1:80:127.0.0.1 http://p1/1.php
curl --resolve p2:80:127.0.0.1 http://p2/2.php

Expected result:

1: /tmp/cache1
S: /tmp/cache1
2: /tmp/cache2
S: /tmp/cache2

Actual result:

1: /tmp/cache1
S: /tmp/cache1
2: /tmp/cache2
S: /tmp/cache1
Workarounds

For me, I ended up with changing the shared framework, and now have to maintain my own fork of it.

You can turn off opcache optimizations.

Another way to work around this is to compile php yourself, with removing the ini_get if block, or even just
changing ini_get to ini_get_opcache_workaround in the zend_optimizer_eval_special_func_call function
in Zend/Optimizer/zend_optimizer.c.

PHP Version

7.2.0 - 8.1.6

Operating System

No response

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu bằng cách đọc Zend/Optimizer/zend_optimizer.c, đặc biệt là điều kiện ini_get và zend_optimizer_eval_special_func_call được nêu trong báo cáo. Chạy bản tái hiện bằng CLI với opcache file caching, sau đó so sánh các giá trị mong đợi và thực tế trong các ví dụ shared-file và virtual-host. Được xem là hoàn tất khi các giá trị PHP_INI_SYSTEM vẫn là giá trị riêng cho từng request hoặc host, đồng thời tính năng tối ưu hóa vẫn được bật.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
c, php
Lĩnh vực
backend, performance
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
45/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.