1
0
Fork 0
mirror of https://github.com/archtechx/tenancy.git synced 2026-05-06 14:44:04 +00:00

Prevent mkdir() race conditions in FilesystemTenancyBootstrapper (#1453)

This prevents race conditions that may occur if there are two concurrent
processes trying to create the storage path for the tenant. The
storagePath() method runs during bootstrap() which can easily happen
in two places at once. The race condition specifically occurs in between
the is_dir() check and the mkdir() call, the latter producing an
exception if the dir already exist. We simply ignore any error coming
out of mkdir() and then check for success separately.

We could omit that success check since failure is unlikely and would
only occur due to a server misconfiguration that would manifest itself
in other ways as well, but this way the simple TOC/TOU race condition
is prevented while other errors are still reported.

We apply the same change to the mkdir() in scopeSessions() as the logic
is similar.

Resolves #1452
This commit is contained in:
Samuel Štancl 2026-04-13 23:57:59 +02:00 committed by GitHub
parent 60dd5226c4
commit e31249dd09
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Stancl\Tenancy\Bootstrappers;
use Exception;
use Illuminate\Foundation\Application;
use Illuminate\Session\FileSessionHandler;
use Illuminate\Support\Facades\Storage;
@ -75,8 +76,13 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
: $this->originalStoragePath . '/framework/cache';
if (! is_dir($path)) {
// Create tenant framework/cache directory if it does not exist
mkdir($path, 0750, true);
// Create tenant framework/cache directory if it does not exist.
// We ignore errors due to TOCTOU race conditions, instead we check for success below.
@mkdir($path, 0750, true);
if (! is_dir($path)) {
throw new Exception("Unable to create tenant storage directory [{$path}].");
}
}
if ($suffix === false) {
@ -222,8 +228,13 @@ class FilesystemTenancyBootstrapper implements TenancyBootstrapper
: $this->originalStoragePath . '/framework/sessions';
if (! is_dir($path)) {
// Create tenant framework/sessions directory if it does not exist
mkdir($path, 0750, true);
// Create tenant framework/sessions directory if it does not exist.
// We ignore errors due to TOCTOU race conditions, instead we check for success below.
@mkdir($path, 0750, true);
if (! is_dir($path)) {
throw new Exception("Unable to create tenant session directory [{$path}].");
}
}
$this->app['config']['session.files'] = $path;