diff --git a/ext/posix/posix.c b/ext/posix/posix.c index b7acf8c751270..76e14f6ecb0c6 100644 --- a/ext/posix/posix.c +++ b/ext/posix/posix.c @@ -744,6 +744,15 @@ PHP_FUNCTION(posix_access) RETURN_FALSE; } + if (mode < 0 || (mode & ~(F_OK | R_OK | W_OK | X_OK))) { + zend_argument_value_error( + 2, + "must be a bitmask of POSIX_F_OK, POSIX_R_OK, POSIX_W_OK, and POSIX_X_OK" + ); + efree(path); + RETURN_THROWS(); + } + ret = access(path, mode); efree(path); diff --git a/ext/posix/tests/posix_access_flags.phpt b/ext/posix/tests/posix_access_flags.phpt new file mode 100644 index 0000000000000..37c7522a2a3b1 --- /dev/null +++ b/ext/posix/tests/posix_access_flags.phpt @@ -0,0 +1,63 @@ +--TEST-- +posix_access() flag (mode) validation +--SKIPIF-- + +--FILE-- +getMessage(), "\n"; +} + +// Invalid: mode with garbage bits +try { + posix_access($testfile, 01000); // S_ISVTX bit (sticky) +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +// Invalid: mode with unrelated high bits +try { + posix_access($testfile, 02000); // S_ISGID bit +} catch (ValueError $e) { + echo $e->getMessage(), "\n"; +} + +// Valid: check read and write access +if (posix_access($testfile, POSIX_R_OK | POSIX_W_OK)) { + echo "Read/write access OK\n"; +} + +// Valid: check file existence +if (posix_access($testfile, POSIX_F_OK)) { + echo "File exists OK\n"; +} + +?> +--CLEAN-- + +--EXPECTF-- +posix_access(): Argument #2 ($flags) must be a bitmask of POSIX_F_OK, POSIX_R_OK, POSIX_W_OK, and POSIX_X_OK +posix_access(): Argument #2 ($flags) must be a bitmask of POSIX_F_OK, POSIX_R_OK, POSIX_W_OK, and POSIX_X_OK +posix_access(): Argument #2 ($flags) must be a bitmask of POSIX_F_OK, POSIX_R_OK, POSIX_W_OK, and POSIX_X_OK +Read/write access OK +File exists OK