php / php/php-src

Incorrect base64 encoding in PHP-FPM with opcache.file_cache_only=1 and sodium

Open
#17,733 25 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Category: Engine Status: Verified
Dominant language
C
Stars
40.4k
Forks
8.1k
Avg merge
2d 13h
Merged PRs (30d)
96

Description

Description

The following code:

<?php

final class SodiumBase64Polyfill
{
    public const SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
    public const SODIUM_BASE64_VARIANT_URLSAFE             = 5;
    public const SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING  = 7;

    public static function bin2base64(string $decoded, int $variant): string
    {
        if (! function_exists('sodium_bin2base64')) {
            return self::bin2base64Fallback($decoded, $variant);
        }

        return sodium_bin2base64($decoded, $variant);
    }

    public static function bin2base64Fallback(string $decoded, int $variant): string
    {
        $encoded = base64_encode($decoded);

        if (
            $variant === self::SODIUM_BASE64_VARIANT_URLSAFE
            || $variant === self::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
        ) {
            $encoded = strtr($encoded, '+/', '-_');
        }

        if (
            $variant === self::SODIUM_BASE64_VARIANT_ORIGINAL_NO_PADDING
            || $variant === self::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING
        ) {
            $encoded = rtrim($encoded, '=');
        }

        return $encoded;
    }
}

var_dump(SodiumBase64Polyfill::bin2base64("Hello world!", SodiumBase64Polyfill::SODIUM_BASE64_VARIANT_URLSAFE_NO_PADDING));

Resulted in this output:

"Hello world!�"

But I expected this output instead:

"SGVsbG8gd29ybGQh"

Steps to reproduce

  1. Run PHP-FPM with the following php.ini settings:
zend_extension=opcache.so
extension=sodium.so
opcache.enable = 1
opcache.enable_cli = 1
; Tune opcache for read-only application files
opcache.revalidate_freq=0
opcache.validate_timestamps=false
opcache.enable_file_override=1

; Enable pre-warmed opcache
opcache.file_cache = "/var/cache/opcache"
opcache.file_cache_read_only=1
opcache.file_cache_consistency_checks=0

; Enable log
opcache.error_log=/dev/stderr
opcache.log_verbosity_level = 4
  1. Compile and run the script using:
php -d zend_extension=opcache.so \
    -d extension=sodium.so \
    -d opcache.enable=1 \
    -d opcache.enable_cli=1 \
    -d opcache.jit=disable \
    -d opcache.file_cache=/var/cache/opcache \
    -d opcache.file_cache_only=1 \
    -d opcache.file_cache_read_only=0 ./public/index.php
  1. Send request php-fpm

Additional information

  • The issue disappears when opcache.optimization_level=0 is set.
  • The bug is tested with the file_cache_only feature introduced in PR #16551, but the issue also reproduces in PHP 8.4.
PHP Version

master, 8.4

Operating System

linux x86 or aarch64

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the failure using the supplied PHP-FPM and CLI commands against public/index.php, with and without opcache.file_cache_only=1 and optimization_level=0. Read the file_cache_only behavior introduced by PR #16551 and trace the interaction with sodium during compilation. Done means the script consistently returns "SGVsbG8gd29ybGQh" under the reported configurations without regressing normal opcache behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
linux, php
Domain
backend, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.