Skip to content

Path::isOwner() hardcodes /tmp instead of using sys_get_temp_dir()#80

Open
manusfreedom wants to merge 1 commit into
joomla-framework:3.x-devfrom
manusfreedom:patch-1
Open

Path::isOwner() hardcodes /tmp instead of using sys_get_temp_dir()#80
manusfreedom wants to merge 1 commit into
joomla-framework:3.x-devfrom
manusfreedom:patch-1

Conversation

@manusfreedom

Copy link
Copy Markdown

Bug Report: Path::isOwner() hardcodes /tmp instead of using sys_get_temp_dir()

Component: libraries/vendor/joomla/filesystem/src/Path.php Method: Path::isOwner()
Affects: Joomla 4.x / 5.x

Note: The content of this bug report and the proposed fix were AI-assisted (generated with Claude). The root cause, reproduction steps, and the process of identifying the issue were found through real investigation and debugging — only the write-up itself was generated with AI assistance.


Summary

Path::isOwner() hardcodes /tmp as the first candidate for a writable temporary directory, instead of using PHP's sys_get_temp_dir(). This causes failures on systems where the PHP temporary directory is configured differently — such as environments with AppArmor, SELinux, open_basedir restrictions, or PrivateTmp=true in systemd — where /tmp may be inaccessible to the php-fpm process.


Steps to Reproduce

  1. Configure php-fpm with a custom temporary directory (e.g. sys_temp_dir = /var/lib/php/tmp in php.ini or pool config)
  2. Restrict access to /tmp via AppArmor, SELinux, or open_basedir
  3. Save Global Configuration in Joomla administrator
  4. Path::isOwner() is called, attempts is_writable('/tmp'), fails, falls through to . (current directory) or session.save_path
  5. AppArmor logs DENIED operation="mknod" on /tmp/<hash>
  6. The UI displays: Joomla\Filesystem\File::delete: Failed deleting <hash>

Root Cause

// Current — hardcoded /tmp, ignores PHP configuration
$dir = is_writable('/tmp') ? '/tmp' : false;

PHP provides sys_get_temp_dir() precisely to abstract the platform/configuration-specific temp directory. It correctly reflects:

  • sys_temp_dir from php.ini
  • upload_tmp_dir fallback
  • Pool-level php_value[sys_temp_dir] overrides
  • OS-level temp dir on Windows (%TEMP%) and non-standard Linux setups

Proposed Fix

// Fixed — respects PHP configuration
$dir = is_writable(sys_get_temp_dir()) ? sys_get_temp_dir() : false;

Full corrected method:

/**
 * Method to determine if script owns the path.
 *
 * @param   string  $path  Path to check ownership.
 *
 * @return  boolean  True if the php script owns the path passed.
 *
 * @since   1.0
 */
public static function isOwner($path)
{
    $tmp = md5(random_bytes(16));
    $ssp = ini_get('session.save_path');
    // Use PHP's configured temp dir instead of hardcoded /tmp
    $dir = is_writable(sys_get_temp_dir()) ? sys_get_temp_dir() : false;
    $dir = !$dir && is_writable('.') ? '.' : $dir;
    $dir = !$dir && is_writable($ssp) ? $ssp : $dir;
    if ($dir) {
        $test = $dir . '/' . $tmp;
        $blank = '';
        File::write($test, $blank, false);
        $return = fileowner($test) === fileowner($path);
        File::delete($test);
        return $return;
    }
    return false;
}

Impact

Area Description
Security Hardcoding /tmp forces administrators to grant php-fpm access to the system /tmp, undermining AppArmor/SELinux confinement and PrivateTmp=true isolation

Environment

  • Joomla 4.x / 5.x
  • php-fpm with AppArmor profile (PrivateTmp=true or custom sys_temp_dir)
  • File: libraries/vendor/joomla/filesystem/src/Path.php

Pull Request for Issue #

Summary of Changes

Testing Instructions

Documentation Changes Required

# Bug Report: `Path::isOwner()` hardcodes `/tmp` instead of using `sys_get_temp_dir()`

**Component:** `libraries/vendor/joomla/filesystem/src/Path.php`  
**Method:** `Path::isOwner()`  
**Affects:** Joomla 4.x / 5.x  

> **Note:** The content of this bug report and the proposed fix were AI-assisted (generated with Claude). The root cause, reproduction steps, and the process of identifying the issue were found through real investigation and debugging — only the write-up itself was generated with AI assistance.

---

## Summary

`Path::isOwner()` hardcodes `/tmp` as the first candidate for a writable temporary directory, instead of using PHP's `sys_get_temp_dir()`. This causes failures on systems where the PHP temporary directory is configured differently — such as environments with AppArmor, SELinux, `open_basedir` restrictions, or `PrivateTmp=true` in systemd — where `/tmp` may be inaccessible to the php-fpm process.

---

## Steps to Reproduce

1. Configure php-fpm with a custom temporary directory (e.g. `sys_temp_dir = /var/lib/php/tmp` in `php.ini` or pool config)
2. Restrict access to `/tmp` via AppArmor, SELinux, or `open_basedir`
3. Save Global Configuration in Joomla administrator
4. `Path::isOwner()` is called, attempts `is_writable('/tmp')`, fails, falls through to `.` (current directory) or `session.save_path`
5. AppArmor logs `DENIED operation="mknod"` on `/tmp/<hash>`
6. The UI displays: `Joomla\Filesystem\File::delete: Failed deleting <hash>`

---

## Root Cause

```php
// Current — hardcoded /tmp, ignores PHP configuration
$dir = is_writable('/tmp') ? '/tmp' : false;
```

PHP provides `sys_get_temp_dir()` precisely to abstract the platform/configuration-specific temp directory. It correctly reflects:

- `sys_temp_dir` from `php.ini`
- `upload_tmp_dir` fallback
- Pool-level `php_value[sys_temp_dir]` overrides
- OS-level temp dir on Windows (`%TEMP%`) and non-standard Linux setups

---

## Proposed Fix

```php
// Fixed — respects PHP configuration
$dir = is_writable(sys_get_temp_dir()) ? sys_get_temp_dir() : false;
```

Full corrected method:

```php
/**
 * Method to determine if script owns the path.
 *
 * @param   string  $path  Path to check ownership.
 *
 * @return  boolean  True if the php script owns the path passed.
 *
 * @SInCE   1.0
 */
public static function isOwner($path)
{
    $tmp = md5(random_bytes(16));
    $ssp = ini_get('session.save_path');
    // Use PHP's configured temp dir instead of hardcoded /tmp
    $dir = is_writable(sys_get_temp_dir()) ? sys_get_temp_dir() : false;
    $dir = !$dir && is_writable('.') ? '.' : $dir;
    $dir = !$dir && is_writable($ssp) ? $ssp : $dir;
    if ($dir) {
        $test = $dir . '/' . $tmp;
        $blank = '';
        File::write($test, $blank, false);
        $return = fileowner($test) === fileowner($path);
        File::delete($test);
        return $return;
    }
    return false;
}
```

---

## Impact

| Area | Description |
|---|---|
| **Security** | Hardcoding `/tmp` forces administrators to grant php-fpm access to the system `/tmp`, undermining AppArmor/SELinux confinement and `PrivateTmp=true` isolation |
| **Correctness** | Ignores explicit PHP configuration (`sys_temp_dir`, pool-level overrides) |
| **Portability** | Breaks on Windows and non-standard Linux setups where `/tmp` does not exist |

---

## Environment

- Joomla 4.x / 5.x
- php-fpm with AppArmor profile (`PrivateTmp=true` or custom `sys_temp_dir`)
- File: `libraries/vendor/joomla/filesystem/src/Path.php`
Copilot AI review requested due to automatic review settings June 15, 2026 14:06

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Updates temporary directory detection to use PHP’s configured temp directory instead of hard-coding /tmp, improving portability across environments.

Changes:

  • Replace /tmp check with sys_get_temp_dir() in Path::isOwner().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Path.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants