Skip to content

Potential deadlock when putenv fails #17403

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
matyhtf opened this issue Jan 8, 2025 · 4 comments
Closed

Potential deadlock when putenv fails #17403

matyhtf opened this issue Jan 8, 2025 · 4 comments

Comments

@matyhtf
Copy link
Contributor

matyhtf commented Jan 8, 2025

Description

https://github.com/php/php-src/blob/master/ext/standard/basic_functions.c#L846

The else branch of the putenv function does not call tsrm_env_unlock() to release the lock, which could potentially lead to a deadlock.

PHP Version

PHP 8.4

Operating System

Ubuntu 22.04

@cmb69
Copy link
Member

cmb69 commented Jan 8, 2025

Needs to be fixed for PHP-8.3+.

@matyhtf
Copy link
Contributor Author

matyhtf commented Jan 8, 2025

Hi cmb69, thanks for your reply.

Another issue is that the implementation of putenv with ZTS may have a bug. Please take a look.

The environ is a global array, if multiple threads concurrently execute putenv with the same key, the pe.previous_value pointer may point to a memory address that has already been freed.

The putenv C function does not copy the string that is passed in; instead, it directly stores the pointer in environ.

Thread 1:

RINIT
putenv(env1)
pe.previous_value = NULL
// ... more code 

Thread 2:

env1 and env2 have the same key

RINIT
putenv(env2)
pe.previous_value = env1

Thread 1:

RSHUTDOWN
// php_putenv_destructor()
free(pe->putenv_string) // free env1

Thread 2:

RSHUTDOWN
// php_putenv_destructor()
// pe->previous_value is env1
putenv(pe->previous_value) // This memory address has already been freed

@nielsdos nielsdos changed the title The lock is not released when putenv fails. Potential deadlock when putenv fails Apr 20, 2025
nielsdos added a commit to nielsdos/php-src that referenced this issue Apr 20, 2025
@nielsdos
Copy link
Member

I understood the deadlock problem and made a PR for it.
I didn't understand the race condition. I don't understand how freeing putenv_string can cause a UAF on previous_value. I also note that grabbing and resetting previous_value happens under the lock.

@nielsdos nielsdos linked a pull request Apr 20, 2025 that will close this issue
@SakiTakamachi
Copy link
Member

SakiTakamachi commented Apr 24, 2025

Since the putenv_entry structure is managed by BG(), in the case of ZTS, each thread should have its own value. Therefore, I don't think it will become a UAF.
Did that actually happen? If so, I may have missed something.

zend_hash_init(&BG(putenv_ht), 1, NULL, php_putenv_destructor, 0);

nielsdos added a commit that referenced this issue Apr 24, 2025
* PHP-8.3:
  Fix GH-17403: Potential deadlock when putenv fails
nielsdos added a commit that referenced this issue Apr 24, 2025
* PHP-8.4:
  Fix GH-17403: Potential deadlock when putenv fails
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants