Skip to content

Add a way to reserve shmop memory ids and prevent shmop_open (e.g. opcache's region) #9951

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

Open
TysonAndre opened this issue Nov 14, 2022 · 3 comments

Comments

@TysonAndre
Copy link
Contributor

TysonAndre commented Nov 14, 2022

Description

shared_segments[i].common.p = shmat(shared_segments[i].shm_id, NULL, 0);

Related to #9944

Prevent accidentally or intentionally reading or writing to shared memory regions which would be used by opcache, or other extensions such as APCu

A possible approach:

  1. Add a helper method in Zend/ directory to track ids used during module initialization
  2. Make the ext/shmop extension check if those ids were already used and treat it like a native error code for https://php.net/shmop_open
  3. Add an ini setting to disable this protection, in case userland debuggers/visualizers have valid use cases for this
@cmb69
Copy link
Member

cmb69 commented Nov 15, 2022

Prevent accidentally or intentionally reading or writing to shared memory regions which would be used by opcache

Couldn't OPcache just use IPC_PRIVATE even for the first segment:

key_t first_segment_key = -1;

@TysonAndre
Copy link
Contributor Author

Couldn't OPcache just use IPC_PRIVATE even for the first segment:

It is. In the windows polyfill, you can attach to the new segment id. https://man7.org/linux/man-pages/man2/shmget.2.html It seems like you can in linux when I manually tested, though the manual didn't make that clear

shared_segments[i].common.p = shmat(shared_segments[i].shm_id, NULL, 0);

TSRM/tsrm_win32.h
75:#define IPC_PRIVATE  0

Test scripts for being able to attach to IPC_PRIVATE(0) from userland on Linux if the id is known

<?php // test.php
$segment = shmop_open(0, 'c', 0666, 20);
var_dump($segment);
$segment2 = shmop_open(0, 'c', 0666, 20);
var_dump($segment2);
var_dump(shmop_write($segment, 'foo', 0));
var_dump(shmop_read($segment, 0, 3));
» sapi/cli/php test.php
old shmid=0
shmid=32827
object(Shmop)#1 (0) {
}
old shmid=32827
shmid=32828
object(Shmop)#2 (0) {
}
int(3)
string(3) "foo"
--- a/ext/shmop/shmop.c
+++ b/ext/shmop/shmop.c
@@ -181,8 +181,16 @@ PHP_FUNCTION(shmop_open)
                zend_argument_value_error(4, "must be greater than 0 for the \"c\" and \"n\" access modes");
                goto err;
        }
+       static int id = 0;
+       if (shmop->key == 0) {
+               shmop->key = id;
+       }
 
+       printf("old shmid=%d\n", (int)shmop->key);
        shmop->shmid = shmget(shmop->key, shmop->size, shmop->shmflg);
+       id = shmop->shmid;
+       printf("shmid=%d\n", (int)shmop->shmid);
+
        if (shmop->shmid == -1) {
                php_error_docref(NULL, E_WARNING, "Unable to attach or create shared memory segment \"%s\"", strerror(errno));
                goto err;

@cmb69
Copy link
Member

cmb69 commented Nov 15, 2022

It seems like you can in linux when I manually tested, though the manual didn't make that clear

Well, it is not guaranteed the IP_PRIVATE == 0, and it might not work for different processes. However, since this ticket is actually about the same process, just disregard my comment.

Note, though, that there is no issue regarding OPcache SHM on Windows, since only memory_model win32 is supported there (but not shm).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants