Private stream wrapper is not safe for mkdir() function calls

Created on 13 November 2020, about 4 years ago
Updated 14 May 2023, over 1 year ago

Problem/Motivation

I have stumbled upon a problem, that on our live server, the

mkdir($uri, $mode, $recursive)

call could not be fulfilled. It seems that there is some private stream wrapper restriction. Therefor a folder cannot be created.

I am not sure how a server can be configured for not allowing private stream wrapper. The public stream wrapper seems to work correctly. Maybe a linux server expert can help here.

Steps to reproduce

1. Install Drupal 9.58

composer create-project drupal/recommended-project:9.5.8 test-project
continue installation via the web UI until complete.

2. Set private file system path in settings.php:

$settings['file_private_path'] = '/var/www/html/private-files';

3. Ensure this directory exists and is readable/writable by the same user that drupal runs as (in my case, webuser/webgroup).

4. Install drush

composer require drush/drush

5. Clear cache

drush cr

6. Create "file upload" field on basic page content type.
Structure -> Content Types -> Basic Page -> Manage Fields
Add Field (File). Set name to "File Upload". Save and continue.
Set upload destination to "private files".
Save field settings
Leave File directory as default ([date:custom:Y]-[date:custom:m])
Save settings

Go to Content -> Add content -> Basic page.

In the File Upload field, Click "Browse..." and select any txt file.

You immediately receive the error message "The file could not be uploaded".

Recent log messages shows:

The upload directory private://2023-05 for the file field field_file_upload could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.

Proposed resolution

Use the realpath as mkdir() parameter.

See the attached patch, which helped me

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Release notes snippet

πŸ› Bug report
Status

Needs work

Version

9.5

Component
File systemΒ  β†’

Last updated about 4 hours ago

Created by

πŸ‡©πŸ‡ͺGermany Peter Majmesku πŸ‡©πŸ‡ͺDΓΌsseldorf

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡³πŸ‡ΏNew Zealand quietone

    @Peter Majmesku, is this a problem?

    There has been no activity here for 2 years, except 10 months ago to ask for steps to reproduce. We need that information to confirm the problem and write tests.

    If you are experiencing this problem on a supported version of Drupal reopen the issue, by setting the status to 'Active', and provide complete steps to reproduce the issue β†’ (starting from "Install Drupal core").

    Since we need more information to move forward with this issue, I am keeping the status at Postponed (maintainer needs more info). If we don't receive additional information to help with the issue, it may be closed after three months.

    Thanks!

  • πŸ‡¨πŸ‡¦Canada jdhildeb

    I am encountering this same issue. I am digging into it, and can reproduce it in my environment.

    This is my analysis:
    * I'm trying to upload a file into Drupal via the UI
    * this causes FileSystem::prepareDirectory() to be called with $uri = 'private://2023-05'
    * my private location is '/var/www/html/private-files' (which exists and is readable/writable by the PHP process)
    * prepareDirectory() calls FileSystem::mkdir(), which calls FileSystem::mkdirCall() in the StreamWrapperManager::getScheme branch.
    * mkdirCall calls back into FileSystem::mkdir()
    * now mkdir() tries to create the directory recursively. In checking file_exists('/var'), it receives FALSE, even though /var exists and is readable by the PHP user.
    * This is where I'm stuck - I don't know why file_exists is returning FALSE. I've tried calling clearstatcache just prior to the file_exists, but file_exists still returns FALSE. I've tried calling file_exists('/var') from a PHP script invoked using 'drush scr myscript.php' - it receives TRUE (and so does not reproduce the issue).
    * Applying patch #6 fixes the issue for me. Drupal successfully creates private://2023-05 (aka /var/www/html/private-files/2023-05) and the upload succeeds. This is evidence that the issue is within Drupal and is not a result of an directory permission issue.

    This is the stack trace at the point that file_exists('/var') returns FALSE:

    ┆ 6609 #0 /var/www/html/web/core/lib/Drupal/Core/StreamWrapper/LocalStream.php(346): Drupal\Core\File\FileSystem->mkdir()\n
    ┆ 6610 #1 [internal function]: Drupal\Core\StreamWrapper\LocalStream->mkdir()\n
    ┆ 6611 #2 /var/www/html/web/core/lib/Drupal/Core/File/FileSystem.php(255): mkdir()\n
    ┆ 6612 #3 /var/www/html/web/core/lib/Drupal/Core/File/FileSystem.php(188): Drupal\Core\File\FileSystem->mkdirCall()\n
    ┆ 6613 #4 /var/www/html/web/core/lib/Drupal/Core/File/FileSystem.php(538): Drupal\Core\File\FileSystem->mkdir()\n
    ┆ 6614 #5 /var/www/html/web/core/modules/file/file.module(1437): Drupal\Core\File\FileSystem->prepareDirectory()\n
    ┆ 6615 #6 /var/www/html/web/core/modules/file/src/Element/ManagedFile.php(76): file_managed_file_save_upload()\n
    ┆ 6616 #7 /var/www/html/web/core/modules/file/src/Plugin/Field/FieldWidget/FileWidget.php(329): Drupal\file\Element\ManagedFile::valueCallback()\n
    ┆ 6617 #8 [internal function]: Drupal\file\Plugin\Field\FieldWidget\FileWidget::value()\n
    (I'm omitting the rest of the stack trace as the above is the relevant part).

  • Status changed to Active over 1 year ago
  • πŸ‡³πŸ‡ΏNew Zealand quietone

    @jdhildeb, thanks for details!

    I am setting this back to active and updated the IS.

  • πŸ‡¨πŸ‡¦Canada jdhildeb

    I have reproduced on a fresh drupal install, so hopefully someone with more knowledge of drupal filesystems can help investigate further.

    Marking active and leaving as "major" because the only reasonable workaround is to upload files to public filesystem, which is not a good option if you are dealing with sensitive documents.

  • Status changed to Needs review over 1 year ago
  • Status changed to Needs work over 1 year ago
  • πŸ‡ΊπŸ‡ΈUnited States SocialNicheGuru

    this breaks http://drupal.org/project/filecache.

    it can no longer make directories.

    "PHP message: Exception: Could not create cache folder /drupal959/html/modules/contrib/filecache/src/Cache/FileSystemBackend.php on line 349 #0 /druapl959/html/modules/contrib/filecache/src/Cache/FileSystemBackend.php(141): Drupal\filecache\Cache\FileSystemBackend->ensureCacheFolderExists('content_block_p...')

Production build 0.71.5 2024