1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix usage of reentrant functions in ext/posix (#13921)

- It's not necessarily an error of sysconf(_SC_GETPW_R_SIZE_MAX) returns -1, as
  specified by posix (and the musl implementation always returns -1). Pick an
  initial buffer size in this case.
- Reentrant variants return an error number an may not set errno
- Implement retry logic for ttyname_r()
- Fix retry logic for getpwnam_r() (pw would be NULL after the first try)
- Test retry logic by setting the initial buffer size to 1 in debug builds
This commit is contained in:
Arnaud Le Blanc
2024-04-11 13:27:39 +02:00
committed by GitHub
parent ea927caffa
commit 66809c05b7

View File

@@ -447,6 +447,7 @@ PHP_FUNCTION(posix_ttyname)
int fd;
#if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX)
zend_long buflen;
int err;
#endif
ZEND_PARSE_PARAMETERS_START(1, 1)
@@ -465,12 +466,23 @@ PHP_FUNCTION(posix_ttyname)
#if defined(ZTS) && defined(HAVE_TTYNAME_R) && defined(_SC_TTY_NAME_MAX)
buflen = sysconf(_SC_TTY_NAME_MAX);
if (buflen < 1) {
RETURN_FALSE;
buflen = 32;
}
#if ZEND_DEBUG
/* Test retry logic */
buflen = 1;
#endif
p = emalloc(buflen);
if (ttyname_r(fd, p, buflen)) {
POSIX_G(last_error) = errno;
try_again:
err = ttyname_r(fd, p, buflen);
if (err) {
if (err == ERANGE) {
buflen *= 2;
p = erealloc(p, buflen);
goto try_again;
}
POSIX_G(last_error) = err;
efree(p);
RETURN_FALSE;
}
@@ -719,6 +731,7 @@ PHP_FUNCTION(posix_getgrnam)
struct group gbuf;
long buflen;
char *buf;
int err;
#endif
ZEND_PARSE_PARAMETERS_START(1, 1)
@@ -728,19 +741,24 @@ PHP_FUNCTION(posix_getgrnam)
#if defined(ZTS) && defined(HAVE_GETGRNAM_R) && defined(_SC_GETGR_R_SIZE_MAX)
buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
if (buflen < 1) {
RETURN_FALSE;
buflen = 1024;
}
#if ZEND_DEBUG
/* Test retry logic */
buflen = 1;
#endif
buf = emalloc(buflen);
try_again:
g = &gbuf;
if (getgrnam_r(name, g, buf, buflen, &g) || g == NULL) {
if (errno == ERANGE) {
err = getgrnam_r(name, g, buf, buflen, &g);
if (err || g == NULL) {
if (err == ERANGE) {
buflen *= 2;
buf = erealloc(buf, buflen);
goto try_again;
}
POSIX_G(last_error) = errno;
POSIX_G(last_error) = err;
efree(buf);
RETURN_FALSE;
}
@@ -768,7 +786,7 @@ PHP_FUNCTION(posix_getgrgid)
{
zend_long gid;
#if defined(ZTS) && defined(HAVE_GETGRGID_R) && defined(_SC_GETGR_R_SIZE_MAX)
int ret;
int err;
struct group _g;
struct group *retgrptr = NULL;
long grbuflen;
@@ -784,20 +802,24 @@ PHP_FUNCTION(posix_getgrgid)
grbuflen = sysconf(_SC_GETGR_R_SIZE_MAX);
if (grbuflen < 1) {
RETURN_FALSE;
grbuflen = 1024;
}
#if ZEND_DEBUG
/* Test retry logic */
grbuflen = 1;
#endif
grbuf = emalloc(grbuflen);
try_again:
ret = getgrgid_r(gid, &_g, grbuf, grbuflen, &retgrptr);
if (ret || retgrptr == NULL) {
if (errno == ERANGE) {
err = getgrgid_r(gid, &_g, grbuf, grbuflen, &retgrptr);
if (err || retgrptr == NULL) {
if (err == ERANGE) {
grbuflen *= 2;
grbuf = erealloc(grbuf, grbuflen);
goto try_again;
}
POSIX_G(last_error) = ret;
POSIX_G(last_error) = err;
efree(grbuf);
RETURN_FALSE;
}
@@ -849,6 +871,7 @@ PHP_FUNCTION(posix_getpwnam)
struct passwd pwbuf;
long buflen;
char *buf;
int err;
#endif
ZEND_PARSE_PARAMETERS_START(1, 1)
@@ -858,20 +881,25 @@ PHP_FUNCTION(posix_getpwnam)
#if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWNAM_R)
buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
if (buflen < 1) {
RETURN_FALSE;
buflen = 1024;
}
#if ZEND_DEBUG
/* Test retry logic */
buflen = 1;
#endif
buf = emalloc(buflen);
pw = &pwbuf;
try_again:
if (getpwnam_r(name, pw, buf, buflen, &pw) || pw == NULL) {
if (errno == ERANGE) {
pw = &pwbuf;
err = getpwnam_r(name, pw, buf, buflen, &pw);
if (err || pw == NULL) {
if (err == ERANGE) {
buflen *= 2;
buf = erealloc(buf, buflen);
goto try_again;
}
efree(buf);
POSIX_G(last_error) = errno;
POSIX_G(last_error) = err;
RETURN_FALSE;
}
#else
@@ -902,7 +930,7 @@ PHP_FUNCTION(posix_getpwuid)
struct passwd *retpwptr = NULL;
long pwbuflen;
char *pwbuf;
int ret;
int err;
#endif
struct passwd *pw;
@@ -913,19 +941,23 @@ PHP_FUNCTION(posix_getpwuid)
#if defined(ZTS) && defined(_SC_GETPW_R_SIZE_MAX) && defined(HAVE_GETPWUID_R)
pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
if (pwbuflen < 1) {
RETURN_FALSE;
pwbuflen = 1024;
}
#if ZEND_DEBUG
/* Test retry logic */
pwbuflen = 1;
#endif
pwbuf = emalloc(pwbuflen);
try_again:
ret = getpwuid_r(uid, &_pw, pwbuf, pwbuflen, &retpwptr);
if (ret || retpwptr == NULL) {
err = getpwuid_r(uid, &_pw, pwbuf, pwbuflen, &retpwptr);
if (err || retpwptr == NULL) {
if (errno == ERANGE) {
pwbuflen *= 2;
pwbuf = erealloc(pwbuf, pwbuflen);
goto try_again;
}
POSIX_G(last_error) = ret;
POSIX_G(last_error) = err;
efree(pwbuf);
RETURN_FALSE;
}