You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This was originally reported in the security report but because it requires access to the FPM configuration (which means basically access to start FPM which is often the root user in typical setup), it wasn't considered as a security issue - such users has already permission to do whatever they want.
The supplied UID and GID to be used by PHP-FPM workers are converted from an unsigned
long type, which could be either 64 or 32 bits unsigned integer depending on the platform,
but are stored in a signed 32 bits integer. This could create confusion with the actual used
UID/GID. Also, a bad UID or GID can make repeatedly crash the workers when setting
UID or GID through setuid or setgid function, because the saved UID and GID are not
verified to be valid before forking.
Here is an additional info from the security report:
Background
For security purposes and because they don't need high privileges, PHP-FPM workers shouldn't run using root privileges. In order to specify the user and group to use, one has to fill the fields user and group in the dedicated worker pool configuration file.
During startup, worker pool configuration is parsed, and stored as a struct fpm_worker_pool_s defined below:
structfpm_worker_pool_s {
structfpm_worker_pool_s*next;
structfpm_worker_pool_s*shared;
structfpm_worker_pool_config_s*config;
char*user, *home;
/* for setting env USER and HOME */enumfpm_address_domainlisten_address_domain;
intlistening_socket;
intset_uid, set_gid;
/* config uid and gid */char*set_user;
/* config user name */intsocket_uid, socket_gid, socket_mode;
/* runtime */structfpm_child_s*children;
intrunning_children;
intidle_spawn_rate;
intwarn_max_children;
#if0intwarn_lq;
#endifstructfpm_scoreboard_s*scoreboard;
intlog_fd;
char**limit_extensions;
/* for ondemand PM */structfpm_event_s*ondemand_event;
intsocket_event_set;
#ifdefHAVE_FPM_ACLvoid*socket_acl;
#endif
};
Worker Pool Configuration
This structure is then later used in order to configure workers during startup phase. The function fpm_unix_conf_wp, defined in fpm_unix.c, handles the worker pool configuration regarding users and groups. It is partially defined below:
staticintfpm_unix_conf_wp(structfpm_worker_pool_s*wp)
{
intis_root= !geteuid();
...
structpasswd*pwd;
intis_root= !geteuid();
if (is_root) {
if (wp->config->user&&*wp->config->user) {
if (fpm_unix_is_id(wp->config->user)) {
wp->set_uid=strtoul(wp->config->user, 0, 10);
pwd=getpwuid(wp->set_uid);
if (pwd) {
wp->set_gid=pwd->pw_gid;
wp->set_user=strdup(pwd->pw_name);
}
}
}
}
}
Integer Overflow Vulnerability
Those fields either accept user names and group names, or UID and GID. When UID or GID are supplied, they are converted from string to an unsigned long type, which is, for example, always an unsigned 64 bits integer on 64 bits Unix platforms. However, it is stored in wp->set_uid, which is a signed 32 bits integer.
This value is then used during worker initialisation, after it has forked, in the fpm_unix_init_child function. The interesting code part is defined below:
if (is_root) {
if (wp->config->process_priority!=64) {
if (setpriority(PRIO_PROCESS, 0, wp->config->process_priority) <0) {
zlog(ZLOG_SYSERROR, "[pool %s] Unable to set priority for this new process",
wp->config->name);
return-1;
}
}
if (wp->set_gid) {
if (0>setgid(wp->set_gid)) {
zlog(ZLOG_SYSERROR, "[pool %s] failed to setgid(%d)",
wp->config->name, wp->set_gid);
return-1;
}
}
if (wp->set_uid) {
if (0>initgroups(wp->set_user ? wp->set_user : wp->config->user,
wp->set_gid)) {
zlog(ZLOG_SYSERROR, "[pool %s] failed to initgroups(%s, %d)",
wp->config->name, wp->config->user, wp->set_gid);
return-1;
}
if (0>setuid(wp->set_uid)) {
zlog(ZLOG_SYSERROR, "[pool %s] failed to setuid(%d)",
wp->config->name, wp->set_uid);
return-1;
}
}
}
Impact
Fields wp->set_uid and wp->set_gid are given as argument to setuid and setgid functions which expects uid_t and gid_t types.
POSIX® documents those type as integers and doesn't mention whether they are signed or unsigned. However the GNU libc defines them as unsigned integers.
At this point, the values can be the one supplied in the configuration file, or another values because they have overflowed during the 64 bits to 32 bits cast. The values also can be invalid regarding the UID or GID of the current running system: the function will return -1 and the worker will shutdown.
Depending on the configuration of the process manager, workers may repeatedly start and crash because of bad UID/GID values.
Activity
bukka commentedon Jul 30, 2025
Here is an additional info from the security report:
Background
For security purposes and because they don't need high privileges, PHP-FPM workers shouldn't run using root privileges. In order to specify the user and group to use, one has to fill the fields
userandgroupin the dedicated worker pool configuration file.During startup, worker pool configuration is parsed, and stored as a struct
fpm_worker_pool_sdefined below:Worker Pool Configuration
This structure is then later used in order to configure workers during startup phase. The function
fpm_unix_conf_wp, defined infpm_unix.c, handles the worker pool configuration regarding users and groups. It is partially defined below:Integer Overflow Vulnerability
Those fields either accept user names and group names, or UID and GID. When UID or GID are supplied, they are converted from string to an unsigned long type, which is, for example, always an unsigned 64 bits integer on 64 bits Unix platforms. However, it is stored in
wp->set_uid, which is a signed 32 bits integer.This value is then used during worker initialisation, after it has forked, in the
fpm_unix_init_childfunction. The interesting code part is defined below:Impact
Fields
wp->set_uidandwp->set_gidare given as argument tosetuidandsetgidfunctions which expectsuid_tandgid_ttypes.POSIX® documents those type as integers and doesn't mention whether they are signed or unsigned. However the GNU libc defines them as unsigned integers.
At this point, the values can be the one supplied in the configuration file, or another values because they have overflowed during the 64 bits to 32 bits cast. The values also can be invalid regarding the UID or GID of the current running system: the function will return -1 and the worker will shutdown.
Depending on the configuration of the process manager, workers may repeatedly start and crash because of bad UID/GID values.
bukka commentedon Jul 30, 2025
Just to add this configuration would always require root user because it doesn't process
userandgroupotherwise...[-]FPM uid and gid overflow issue[/-][+]FPM uid and gid overflow[/+]Fix GH-19320: Prevent FPM UID and GID overflow (#22986)
Merge branch 'PHP-8.4' into PHP-8.5
Merge branch 'PHP-8.5'