-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Allow numeric [UG]ID in FPM listen.{owner,group} #5148
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
Conversation
So, there were CI failures but they seem unrelated to the PR. This patch is useful for users with remote user databases (e.g. LDAP), where there's an inherent race between user creation and FPM pool creation. When the pool is created before the user has been created, FPM dies on reload due to the nonexistent user, taking down all pools. Accepting numeric IDs would prevent this from happening. |
Looks fine to me, but let's let @bukka have a look as well. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that it makes sense in general.
It might be also possible to add some basic tests. It will be probably reliable only for the current user and some non existent user for errors. That should be enough to verify that uid and gid is accepted.
@@ -163,27 +163,35 @@ int fpm_unix_resolve_socket_premissions(struct fpm_worker_pool_s *wp) /* {{{ */ | |||
#endif | |||
|
|||
if (c->listen_owner && *c->listen_owner) { | |||
struct passwd *pwd; | |||
if (strlen(c->listen_owner) == strspn(c->listen_owner, "0123456789")) { | |||
wp->socket_uid = strtoul(c->listen_owner, 0, 10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please verify that the uid exists using getpwuid
and fail if it doesn't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The motivation for this patch is to allow the code to work even when UID and GID don't correspond to a valid used (yet). The use case is for situations where creating the user might take longer than creating the pool when using remote authentication, like when using LDAP, and using the numeric IDs would allow FPM to successfully be reloaded when the pool is created, even if the user does not yet exist.
The patch mirrors the code for the user
and group
settings, which also do not fail if the IDs are not found.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok that makes sense.
} | ||
|
||
if (c->listen_group && *c->listen_group) { | ||
struct group *grp; | ||
if (strlen(c->listen_group) == strspn(c->listen_group, "0123456789")) { | ||
wp->socket_gid = strtoul(c->listen_group, 0, 10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please verify that the gid exists using getgrgid
and fail if it doesn't.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please see my comment w.r.t listen_owner
above.
So the only missing bit is a test. Otherwise it looks good. |
I've added a simple test file. |
I believe the tests failed because they're not run as root. Is there a way to skip a test case unless it's running as root? Edit: I've added a commit for that, thought I'm not sure it's the best way. |
EOT; | ||
|
||
$tester = new FPM\Tester($cfg); | ||
$tester->start(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just tested this to run under root and it actually fails to start for me. Might be my local issue but was wondering if the test actually works for you when you run it under root?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Btw for me this line fails if run under root even with setting TEST_FPM_RUN_AS_ROOT=1
:
$this->masterProcess = proc_open($cmd, $desc, $pipes);
Interestingly I tested starting that with passthru and it actually starts FPM so something weird with proc_open
. Might need to debug it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does work for me:
$ sudo -i
# cd /home/andre/git/forks/php-src
# TEST_FPM_RUN_AS_ROOT=1 ./sapi/cli/php run-tests.php sapi/fpm/tests/socket-uds-numeric-user-and-group-id.phpt
=====================================================================
PHP : /home/andre/git/forks/php-src/sapi/cli/php
PHP_SAPI : cli
PHP_VERSION : 8.0.0-dev
ZEND_VERSION: 4.0.0-dev
PHP_OS : Linux - Linux andre 4.15.0-88-generic #88-Ubuntu SMP Tue Feb 11 20:11:34 UTC 2020 x86_64
INI actual : /home/andre/git/forks/php-src
More .INIs :
---------------------------------------------------------------------
PHP : /home/andre/git/forks/php-src/sapi/phpdbg/phpdbg
PHP_SAPI : phpdbg
PHP_VERSION : 8.0.0-dev
ZEND_VERSION: 4.0.0-dev
PHP_OS : Linux - Linux andre 4.15.0-88-generic #88-Ubuntu SMP Tue Feb 11 20:11:34 UTC 2020 x86_64
INI actual : /home/andre/git/forks/php-src
More .INIs :
---------------------------------------------------------------------
CWD : /home/andre/git/forks/php-src
Extra dirs :
VALGRIND : Not used
=====================================================================
Running selected tests.
PASS FPM: UNIX socket owner and group settings can be numeric [sapi/fpm/tests/socket-uds-numeric-user-and-group-id.phpt]
=====================================================================
Number of tests : 1 1
Tests skipped : 0 ( 0.0%) --------
Tests warned : 0 ( 0.0%) ( 0.0%)
Tests failed : 0 ( 0.0%) ( 0.0%)
Tests passed : 1 (100.0%) (100.0%)
---------------------------------------------------------------------
Time taken : 0 seconds
=====================================================================
The test calls the stat
command to check the owner and group of the created sockets. Could it be a PATH
issue, or maybe your environment doesn't have this command?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably something local then. Don't worry about it then!
*/ | ||
static public function skipIfNotRoot() | ||
{ | ||
if (getmyuid() != 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem correct as it's just for the actual script owner but we should care about the EUID so it should be more something like this:
if (
(extension_loaded('posix_geteuid') && posix_geteuid() !== 0) ||
(exec('id -u', $output, $rv) !== "0")
) {
die('skip not running as root');
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I didn't know that's what getmyuid
did. However the test still works as intended because when the test is run as root, the PHP script generated from the phpt file will be owned by root, and so getmyuid
will return 0.
I can add a commit to replace the test as you suggested, but in skipif.inc
there's a similar check that also uses getmyuid
:
// Running as root is not allowed without TEST_FPM_RUN_AS_ROOT env
if (!getmyuid() && !getenv('TEST_FPM_RUN_AS_ROOT')) {
die('skip Refusing to run as root');
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah it should be enough then. I sometimes test things just by running php on the phpt file (without the framework) so that's why it didn't work for me but that's not requirement for the test to work so feel free to leave it as it is.
That root test looks like a good idea and it would be also good to have root tests for other things so well done on starting that! The only thing about those tests is that we won't be currently able to run them in CI. I think it would be idea to also have a test that we can run in CI. It could be basically the same as the current one, just it would use |
I've added a test that works as you suggested. I couldn't find a way to use PHP code or template variables in the |
So, the test does work locally, but it's failing in the CI environment:
I don't know enough about the CI environment to understand why this happens. Do the tests run as a different user than the one who owns the test files? |
it might be that Azure pipeline might be using seccomp or something maybe. Might make sense to skip just in there maybe as it works in Travis. @nikic is it possible to skip Azure pipelines easily? |
Looks like that did it. There's still a failure on macos though
|
I think renaming the test files to something shorter will fix that. |
@andrenth It all looks good, just one small thing. Please can you update www.conf.in to somehow state that uid and gid are supported. Currently the description in there ( Lines 42 to 44 in 4c0ddd0
|
I've added a short note that those settings accept either names or numeric IDs. If you'd like me to extend the explanation a bit more, let me know. |
Yeah I think it's good enough. Can you please squash all your commits and push force it? |
64d0e8a
to
ac56ce1
Compare
Done. |
Merged to 7.4 as 0b4e80b |
Thank you! |
Nice patch! |
This patch allows FPM pool configuration settings
listen.owner
andlisten.group
to accept numeric IDs as well as user and group names. This makes them mirror the behavior of theuser
andgroup
settings.This feature was requested on bug #77062 in the bug tracker