Skip to content

Add warning to log, when fpm socket was not registered on the expected path #11066

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion sapi/fpm/fpm/fpm_sockets.c
Original file line number Diff line number Diff line change
Expand Up @@ -396,9 +396,25 @@ static int fpm_socket_af_inet_listening_socket(struct fpm_worker_pool_s *wp) /*
static int fpm_socket_af_unix_listening_socket(struct fpm_worker_pool_s *wp) /* {{{ */
{
struct sockaddr_un sa_un;
size_t socket_length = sizeof(sa_un.sun_path);
size_t address_length = strlen(wp->config->listen_address);

memset(&sa_un, 0, sizeof(sa_un));
strlcpy(sa_un.sun_path, wp->config->listen_address, sizeof(sa_un.sun_path));
strlcpy(sa_un.sun_path, wp->config->listen_address, socket_length);

if (address_length >= socket_length) {
zlog(
ZLOG_WARNING,
"[pool %s] cannot bind to UNIX socket '%s' as path is too long (found length: %zu, "
"maximal length: %zu), trying cut socket path instead '%s'",
wp->config->name,
wp->config->listen_address,
address_length,
socket_length,
sa_un.sun_path
);
}

sa_un.sun_family = AF_UNIX;
return fpm_sockets_get_listening_socket(wp, (struct sockaddr *) &sa_un, sizeof(struct sockaddr_un));
}
Expand Down
31 changes: 30 additions & 1 deletion sapi/fpm/fpm/fpm_unix.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/un.h>
#include <pwd.h>
#include <grp.h>

Expand Down Expand Up @@ -63,6 +64,33 @@ static struct passwd *fpm_unix_get_passwd(struct fpm_worker_pool_s *wp, const ch
return pwd;
}

static inline bool fpm_unix_check_listen_address(struct fpm_worker_pool_s *wp, const char *address, int flags)
{
if (wp->listen_address_domain != FPM_AF_UNIX) {
return true;
}

struct sockaddr_un test_socket;
size_t address_length = strlen(address);
size_t socket_length = sizeof(test_socket.sun_path);

if (address_length < socket_length) {
return true;
}

zlog(
flags,
"[pool %s] cannot bind to UNIX socket '%s' as path is too long (found length: %zu, "
"maximal length: %zu)",
wp->config->name,
address,
address_length,
socket_length
);

return false;
}

static inline bool fpm_unix_check_passwd(struct fpm_worker_pool_s *wp, const char *name, int flags)
{
return !name || fpm_unix_is_id(name) || fpm_unix_get_passwd(wp, name, flags);
Expand Down Expand Up @@ -90,6 +118,7 @@ bool fpm_unix_test_config(struct fpm_worker_pool_s *wp)
return (
fpm_unix_check_passwd(wp, config->user, ZLOG_ERROR) &&
fpm_unix_check_group(wp, config->group, ZLOG_ERROR) &&
fpm_unix_check_listen_address(wp, config->listen_address, ZLOG_SYSERROR) &&
fpm_unix_check_passwd(wp, config->listen_owner, ZLOG_SYSERROR) &&
fpm_unix_check_group(wp, config->listen_group, ZLOG_SYSERROR)
);
Expand Down Expand Up @@ -273,7 +302,7 @@ int fpm_unix_set_socket_permissions(struct fpm_worker_pool_s *wp, const char *pa
/* Copy the new ACL entry from config */
for (i=ACL_FIRST_ENTRY ; acl_get_entry(aclconf, i, &entryconf) ; i=ACL_NEXT_ENTRY) {
if (0 > acl_create_entry (&aclfile, &entryfile) ||
0 > acl_copy_entry(entryfile, entryconf)) {
0 > acl_copy_entry(entryfile, entryconf)) {
zlog(ZLOG_SYSERROR, "[pool %s] failed to add entry to the ACL of the socket '%s'", wp->config->name, path);
acl_free(aclfile);
return -1;
Expand Down
2 changes: 1 addition & 1 deletion sapi/fpm/tests/logreader.inc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class LogReader
*
* @var string|null
*/
private ?string $currentSourceName;
private ?string $currentSourceName = null;

/**
* Log descriptors.
Expand Down
74 changes: 74 additions & 0 deletions sapi/fpm/tests/socket-uds-too-long-filename-start.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
--TEST--
FPM: UNIX socket filename is too for start
--SKIPIF--
<?php
include "skipif.inc"; ?>
--FILE--
<?php

require_once "tester.inc";
$socketFilePrefix = __DIR__ . '/socket-file';
$socketFile = sprintf(
"%s-fpm-unix-socket-too-long-filename-but-starts-anyway%s.sock",
$socketFilePrefix,
str_repeat('-0000', 11)
);

$cfg = <<<EOT
[global]
error_log = {{FILE:LOG}}

[fpm_pool]
listen = $socketFile
pm = static
pm.max_children = 1
catch_workers_output = yes
EOT;

$tester = new FPM\Tester($cfg);
$tester->start();
$tester->expectLogStartNotices();
$tester->expectLogPattern(
sprintf(
'/\[pool fpm_pool\] cannot bind to UNIX socket \'%s\' as path is too long '
. '\(found length: %d, maximal length: \d+\), trying cut socket path instead \'.+\'/',
preg_quote($socketFile, '/'),
strlen($socketFile)
),
true
);

$files = glob($socketFilePrefix . '*');

if ($files === []) {
echo 'Socket files were not found.' . PHP_EOL;
}

if ($socketFile === $files[0]) {
// this means the socket file path length is not an issue (anymore). Might be not long enough
echo 'Socket file is the same as configured.' . PHP_EOL;
}

$tester->terminate();
$tester->expectLogTerminatingNotices();
$tester->close();
?>
Done
--EXPECT--
Done
--CLEAN--
<?php
require_once "tester.inc";
FPM\Tester::clean();

// cleanup socket file if php-fpm was not killed
$socketFile = sprintf(
"/socket-file-fpm-unix-socket-too-long-filename-but-starts-anyway%s.sock",
__DIR__,
str_repeat('-0000', 11)
);

if (is_file($socketFile)) {
unlink($socketFile);
}
?>
47 changes: 47 additions & 0 deletions sapi/fpm/tests/socket-uds-too-long-filename-test.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
--TEST--
FPM: UNIX socket filename is too for test
--SKIPIF--
<?php
include "skipif.inc"; ?>
--FILE--
<?php

require_once "tester.inc";

$socketFilePrefix = __DIR__ . '/socket-file';
$socketFile = sprintf(
"/socket-file-fpm-unix-socket-too-long-filename-but-starts-anyway%s.sock",
__DIR__,
str_repeat('-0000', 11)
);

$cfg = <<<EOT
[global]
error_log = {{FILE:LOG}}

[fpm_pool]
listen = $socketFile
pm = static
pm.max_children = 1
catch_workers_output = yes
EOT;

$tester = new FPM\Tester($cfg);
$tester->testConfig(true, [
sprintf(
'/cannot bind to UNIX socket \'%s\' as path is too long '
. '\(found length: %d, maximal length: \d+\)/',
preg_quote($socketFile, '/'),
strlen($socketFile)
),
'/FPM initialization failed/',
]);
?>
Done
--EXPECT--
Done
--CLEAN--
<?php
require_once "tester.inc";
FPM\Tester::clean();
?>
46 changes: 40 additions & 6 deletions sapi/fpm/tests/tester.inc
Original file line number Diff line number Diff line change
Expand Up @@ -382,26 +382,50 @@ class Tester
* @return null|array
* @throws \Exception
*/
public function testConfig($silent = false)
public function testConfig($silent = false, array|string|null $expectedPattern = null): ?array
{
$configFile = $this->createConfig();
$cmd = self::findExecutable() . ' -n -tt -y ' . $configFile . ' 2>&1';
$this->trace('Testing config using command', $cmd, true);
exec($cmd, $output, $code);
$found = 0;
if ($expectedPattern !== null) {
$expectedPatterns = is_array($expectedPattern) ? $expectedPattern : [$expectedPattern];
}
if ($code) {
$messages = [];
foreach ($output as $outputLine) {
$message = preg_replace("/\[.+?\]/", "", $outputLine, 1);
if ($expectedPattern !== null) {
for ($i = 0; $i < count($expectedPatterns); $i++) {
$pattern = $expectedPatterns[$i];
if ($pattern !== null && preg_match($pattern, $message)) {
$found++;
$expectedPatterns[$i] = null;
}
}
}
$messages[] = $message;
if ( ! $silent) {
$this->error($message, null, false);
}
}
} else {
$messages = null;
}

return $messages;
if ($expectedPattern !== null && $found < count($expectedPatterns)) {
$missingPatterns = array_filter($expectedPatterns);
$errorMessage = sprintf(
"The expected config %s %s %s not been found",
count($missingPatterns) > 1 ? 'patterns' : 'pattern',
implode(', ', $missingPatterns),
count($missingPatterns) > 1 ? 'have' : 'has',
);
$this->error($errorMessage);
}

return null;
return $messages;
}

/**
Expand Down Expand Up @@ -1155,9 +1179,19 @@ class Tester
return $address;
}

return sys_get_temp_dir() . '/' .
hash('crc32', dirname($address)) . '-' .
basename($address);
$addressPart = hash('crc32', dirname($address)) . '-' . basename($address);

// is longer on Mac, than on Linux
$tmpDirAddress = sys_get_temp_dir() . '/' . $addressPart;
;

if (strlen($tmpDirAddress) <= 104) {
return $tmpDirAddress;
}

$srcRootAddress = dirname(__DIR__, 3) . '/' . $addressPart;

return $srcRootAddress;
}

return $this->getHost($type) . ':' . $port;
Expand Down