Add support for sensitive parameters in stubs

This commit is contained in:
Máté Kocsis 2022-06-02 15:11:48 +02:00
parent 49951165f0
commit debd38f851
27 changed files with 172 additions and 67 deletions

View file

@ -109,7 +109,7 @@ void zend_startup_constants(void)
void zend_register_standard_constants(void)
{
register_zend_constants_consts(0);
register_zend_constants_symbols(0);
REGISTER_MAIN_LONG_CONSTANT("DEBUG_BACKTRACE_PROVIDE_OBJECT", DEBUG_BACKTRACE_PROVIDE_OBJECT, CONST_PERSISTENT | CONST_CS);
REGISTER_MAIN_LONG_CONSTANT("DEBUG_BACKTRACE_IGNORE_ARGS", DEBUG_BACKTRACE_IGNORE_ARGS, CONST_PERSISTENT | CONST_CS);

View file

@ -3,7 +3,7 @@
static void register_zend_constants_consts(int module_number)
static void register_zend_constants_symbols(int module_number)
{
REGISTER_LONG_CONSTANT("E_ERROR", E_ERROR, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("E_WARNING", E_WARNING, CONST_CS | CONST_PERSISTENT);

View file

@ -759,13 +759,24 @@ class ArgInfo {
public $phpDocType;
/** @var string|null */
public $defaultValue;
/** @var bool */
public $isSensitive;
public function __construct(string $name, int $sendBy, bool $isVariadic, ?Type $type, ?Type $phpDocType, ?string $defaultValue) {
public function __construct(
string $name,
int $sendBy,
bool $isVariadic,
?Type $type,
?Type $phpDocType,
?string $defaultValue,
bool $isSensitive
) {
$this->name = $name;
$this->sendBy = $sendBy;
$this->isVariadic = $isVariadic;
$this->setTypes($type, $phpDocType);
$this->defaultValue = $defaultValue;
$this->isSensitive = $isSensitive;
}
public function equals(ArgInfo $other): bool {
@ -773,7 +784,8 @@ class ArgInfo {
&& $this->sendBy === $other->sendBy
&& $this->isVariadic === $other->isVariadic
&& Type::equals($this->type, $other->type)
&& $this->defaultValue === $other->defaultValue;
&& $this->defaultValue === $other->defaultValue
&& $this->isSensitive === $other->isSensitive;
}
public function getSendByString(): string {
@ -925,6 +937,7 @@ interface FunctionOrMethodName {
public function getDeclaration(): string;
public function getArgInfoName(): string;
public function getMethodSynopsisFilename(): string;
public function getAttributeName(): string;
public function __toString(): string;
public function isMethod(): bool;
public function isConstructor(): bool;
@ -970,6 +983,10 @@ class FunctionName implements FunctionOrMethodName {
return implode('_', $this->name->parts);
}
public function getAttributeName(): string {
return strtolower($this->name->toString());
}
public function __toString(): string {
return $this->name->toString();
}
@ -989,7 +1006,7 @@ class FunctionName implements FunctionOrMethodName {
class MethodName implements FunctionOrMethodName {
/** @var Name */
private $className;
public $className;
/** @var string */
public $methodName;
@ -1014,6 +1031,10 @@ class MethodName implements FunctionOrMethodName {
return $this->getDeclarationClassName() . "_{$this->methodName}";
}
public function getAttributeName(): string {
return strtolower($this->methodName);
}
public function __toString(): string {
return "$this->className::$this->methodName";
}
@ -2896,7 +2917,7 @@ class DocCommentTag {
if ($this->name === "param") {
preg_match('/^\s*[\w\|\\\\\[\]]+\s*\$(\w+).*$/', $value, $matches);
} elseif ($this->name === "prefer-ref") {
} elseif ($this->name === "prefer-ref" || $this->name === "sensitive-param") {
preg_match('/^\s*\$(\w+).*$/', $value, $matches);
}
@ -2946,13 +2967,9 @@ function parseFunctionLike(
if ($comment) {
$tags = parseDocComment($comment);
foreach ($tags as $tag) {
if ($tag->name === 'prefer-ref') {
$varName = $tag->getVariableName();
if (!isset($paramMeta[$varName])) {
$paramMeta[$varName] = [];
}
$paramMeta[$varName]['preferRef'] = true;
} else if ($tag->name === 'alias' || $tag->name === 'implementation-alias') {
switch ($tag->name) {
case 'alias':
case 'implementation-alias':
$aliasType = $tag->name;
$aliasParts = explode("::", $tag->getValue());
if (count($aliasParts) === 1) {
@ -2960,20 +2977,44 @@ function parseFunctionLike(
} else {
$alias = new MethodName(new Name($aliasParts[0]), $aliasParts[1]);
}
} else if ($tag->name === 'deprecated') {
break;
case 'deprecated':
$isDeprecated = true;
} else if ($tag->name === 'no-verify') {
break;
case 'no-verify':
$verify = false;
} else if ($tag->name === 'tentative-return-type') {
break;
case 'tentative-return-type':
$tentativeReturnType = true;
} else if ($tag->name === 'return') {
break;
case 'return':
$docReturnType = $tag->getType();
} else if ($tag->name === 'param') {
break;
case 'param':
$docParamTypes[$tag->getVariableName()] = $tag->getType();
} else if ($tag->name === 'refcount') {
break;
case 'refcount':
$refcount = $tag->getValue();
} else if ($tag->name === 'compile-time-eval') {
break;
case 'compile-time-eval':
$supportsCompileTimeEval = true;
break;
case 'prefer-ref':
case 'sensitive-param':
$varName = $tag->getVariableName();
if (!isset($paramMeta[$varName])) {
$paramMeta[$varName] = [];
}
$paramMeta[$varName][$tag->name] = true;
break;
}
}
}
@ -2984,7 +3025,8 @@ function parseFunctionLike(
$foundVariadic = false;
foreach ($func->getParams() as $i => $param) {
$varName = $param->var->name;
$preferRef = !empty($paramMeta[$varName]['preferRef']);
$preferRef = !empty($paramMeta[$varName]['prefer-ref']);
$isSensitive = !empty($paramMeta[$varName]['sensitive-param']);
unset($paramMeta[$varName]);
if (isset($varNameSet[$varName])) {
@ -3031,7 +3073,8 @@ function parseFunctionLike(
$param->variadic,
$type,
isset($docParamTypes[$varName]) ? Type::fromString($docParamTypes[$varName]) : null,
$param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null
$param->default ? $prettyPrinter->prettyPrintExpr($param->default) : null,
$isSensitive
);
if (!$param->default && !$param->variadic) {
$numRequiredArgs = $i + 1;
@ -3555,7 +3598,11 @@ function findEquivalentFuncInfo(array $generatedFuncInfos, FuncInfo $funcInfo):
return null;
}
/** @param iterable $infos */
/**
* @template T
* @param iterable<T> $infos
* @param Closure(T): string|null $codeGenerator
*/
function generateCodeWithConditions(
iterable $infos, string $separator, Closure $codeGenerator): string {
$code = "";
@ -3593,7 +3640,7 @@ function generateArgInfoCode(
$generatedFuncInfos = [];
$code .= generateCodeWithConditions(
$fileInfo->getAllFuncInfos(), "\n",
function (FuncInfo $funcInfo) use(&$generatedFuncInfos) {
static function (FuncInfo $funcInfo) use (&$generatedFuncInfos) {
/* If there already is an equivalent arginfo structure, only emit a #define */
if ($generatedFuncInfo = findEquivalentFuncInfo($generatedFuncInfos, $funcInfo)) {
$code = sprintf(
@ -3615,7 +3662,7 @@ function generateArgInfoCode(
$generatedFunctionDeclarations = [];
$code .= generateCodeWithConditions(
$fileInfo->getAllFuncInfos(), "",
function (FuncInfo $funcInfo) use($fileInfo, &$generatedFunctionDeclarations) {
static function (FuncInfo $funcInfo) use ($fileInfo, &$generatedFunctionDeclarations) {
$key = $funcInfo->getDeclarationKey();
if (isset($generatedFunctionDeclarations[$key])) {
return null;
@ -3636,14 +3683,27 @@ function generateArgInfoCode(
}
if ($fileInfo->generateClassEntries) {
if (!empty($fileInfo->constInfos)) {
$code .= "\nstatic void register_{$stubFilenameWithoutExtension}_consts(int module_number)\n";
$classEntriesWithSensitiveParams = [];
$attributeInitializationCode = generateAttributeInitialization($fileInfo, $classEntriesWithSensitiveParams);
if ($attributeInitializationCode !== "" || !empty($fileInfo->constInfos)) {
$classEntriesWithSensitiveParams = array_unique($classEntriesWithSensitiveParams);
$code .= "\nstatic void register_{$stubFilenameWithoutExtension}_symbols(int module_number";
foreach ($classEntriesWithSensitiveParams as $ce) {
$code .= ", zend_class_entry *$ce";
}
$code .= ")\n";
$code .= "{\n";
foreach ($fileInfo->constInfos as $constInfo) {
$code .= $constInfo->getDeclaration($allConstInfos);
}
if (!empty($attributeInitializationCode !== "" && $fileInfo->constInfos)) {
$code .= "\n";
}
$code .= $attributeInitializationCode;
$code .= "}\n";
}
@ -3677,7 +3737,7 @@ function generateFunctionEntries(?Name $className, array $funcInfos): string {
}
$code .= "\n\nstatic const zend_function_entry {$functionEntryName}[] = {\n";
$code .= generateCodeWithConditions($funcInfos, "", function (FuncInfo $funcInfo) {
$code .= generateCodeWithConditions($funcInfos, "", static function (FuncInfo $funcInfo) {
return $funcInfo->getFunctionEntry();
});
$code .= "\tZEND_FE_END\n";
@ -3686,6 +3746,34 @@ function generateFunctionEntries(?Name $className, array $funcInfos): string {
return $code;
}
function generateAttributeInitialization(FileInfo $fileInfo, array &$classEntriesWithSensitiveParams): string {
return generateCodeWithConditions(
$fileInfo->getAllFuncInfos(),
"",
static function (FuncInfo $funcInfo) use (&$classEntriesWithSensitiveParams) {
$code = null;
foreach ($funcInfo->args as $index => $arg) {
if (!$arg->isSensitive) {
continue;
}
if ($funcInfo->name instanceof MethodName) {
$classEntry = "class_entry_" . str_replace("\\", "_", $funcInfo->name->className->toString());
$functionTable = "&{$classEntry}->function_table";
$classEntriesWithSensitiveParams[] = $classEntry;
} else {
$functionTable = "CG(function_table)";
}
$code .= " zend_mark_function_parameter_as_sensitive($functionTable, \"" . $funcInfo->name->getAttributeName() . "\", $index);\n";
}
return $code;
}
);
}
/** @param FuncInfo<string, FuncInfo> $funcInfos */
function generateOptimizerInfo(array $funcInfos): string {
@ -3693,7 +3781,7 @@ function generateOptimizerInfo(array $funcInfos): string {
$code .= "static const func_info_t func_infos[] = {\n";
$code .= generateCodeWithConditions($funcInfos, "", function (FuncInfo $funcInfo) {
$code .= generateCodeWithConditions($funcInfos, "", static function (FuncInfo $funcInfo) {
return $funcInfo->getOptimizerInfo();
});

View file

@ -110,7 +110,7 @@ ZEND_GET_MODULE(calendar)
PHP_MINIT_FUNCTION(calendar)
{
register_calendar_consts(module_number);
register_calendar_symbols(module_number);
return SUCCESS;
}

View file

@ -117,7 +117,7 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE_END
};
static void register_calendar_consts(int module_number)
static void register_calendar_symbols(int module_number)
{
REGISTER_LONG_CONSTANT("CAL_GREGORIAN", CAL_GREGORIAN, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("CAL_JULIAN", CAL_JULIAN, CONST_CS | CONST_PERSISTENT);

View file

@ -401,8 +401,8 @@ ZEND_MODULE_POST_ZEND_DEACTIVATE_D(date)
PHP_MINIT_FUNCTION(date)
{
REGISTER_INI_ENTRIES();
register_php_date_consts(module_number);
date_register_classes();
register_php_date_symbols(module_number);
php_date_global_timezone_db = NULL;
php_date_global_timezone_db_enabled = 0;

View file

@ -748,7 +748,7 @@ static const zend_function_entry class_DatePeriod_methods[] = {
ZEND_FE_END
};
static void register_php_date_consts(int module_number)
static void register_php_date_symbols(int module_number)
{
REGISTER_STRING_CONSTANT("DATE_ATOM", DATE_FORMAT_RFC3339, CONST_CS | CONST_PERSISTENT);
ZEND_ASSERT(strcmp(DATE_FORMAT_RFC3339, "Y-m-d\\TH:i:sP") == 0);

View file

@ -789,7 +789,7 @@ PHP_MINIT_FUNCTION(dom)
zend_hash_add_ptr(&classes, dom_xpath_class_entry->name, &dom_xpath_prop_handlers);
#endif
register_php_dom_consts(module_number);
register_php_dom_symbols(module_number);
php_libxml_register_export(dom_node_class_entry, php_dom_export_node);

View file

@ -895,7 +895,7 @@ static const zend_function_entry class_DOMXPath_methods[] = {
ZEND_FE_END
};
static void register_php_dom_consts(int module_number)
static void register_php_dom_symbols(int module_number)
{
REGISTER_LONG_CONSTANT("XML_ELEMENT_NODE", XML_ELEMENT_NODE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("XML_ATTRIBUTE_NODE", XML_ATTRIBUTE_NODE, CONST_CS | CONST_PERSISTENT);

View file

@ -207,7 +207,7 @@ PHP_MINIT_FUNCTION(enchant)
enchant_dict_handlers.clone_obj = NULL;
enchant_dict_handlers.compare = zend_objects_not_comparable;
register_enchant_consts(module_number);
register_enchant_symbols(module_number);
return SUCCESS;
}

View file

@ -158,7 +158,7 @@ static const zend_function_entry class_EnchantDictionary_methods[] = {
ZEND_FE_END
};
static void register_enchant_consts(int module_number)
static void register_enchant_symbols(int module_number)
{
REGISTER_LONG_CONSTANT("ENCHANT_MYSPELL", PHP_ENCHANT_MYSPELL, CONST_CS | CONST_PERSISTENT | CONST_DEPRECATED);
REGISTER_LONG_CONSTANT("ENCHANT_ISPELL", PHP_ENCHANT_ISPELL, CONST_CS | CONST_PERSISTENT | CONST_DEPRECATED);

View file

@ -166,7 +166,7 @@ PHP_MINIT_FUNCTION(exif)
{
REGISTER_INI_ENTRIES();
register_exif_consts(module_number);
register_exif_symbols(module_number);
return SUCCESS;
}

View file

@ -38,7 +38,7 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE_END
};
static void register_exif_consts(int module_number)
static void register_exif_symbols(int module_number)
{
REGISTER_LONG_CONSTANT("EXIF_USE_MBSTRING", USE_MBSTRING, CONST_CS | CONST_PERSISTENT);
}

View file

@ -115,7 +115,7 @@ PHP_MINIT_FUNCTION(finfo)
finfo_object_handlers.free_obj = finfo_objects_free;
finfo_object_handlers.clone_obj = NULL;
register_fileinfo_consts(module_number);
register_fileinfo_symbols(module_number);
return SUCCESS;
}

View file

@ -82,7 +82,7 @@ static const zend_function_entry class_finfo_methods[] = {
ZEND_FE_END
};
static void register_fileinfo_consts(int module_number)
static void register_fileinfo_symbols(int module_number)
{
REGISTER_LONG_CONSTANT("FILEINFO_NONE", MAGIC_NONE, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FILEINFO_SYMLINK", MAGIC_SYMLINK, CONST_CS | CONST_PERSISTENT);

View file

@ -162,7 +162,7 @@ PHP_MINIT_FUNCTION(filter)
REGISTER_INI_ENTRIES();
register_filter_consts(module_number);
register_filter_symbols(module_number);
sapi_register_input_filter(php_sapi_filter, php_sapi_filter_init);

View file

@ -59,7 +59,7 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE_END
};
static void register_filter_consts(int module_number)
static void register_filter_symbols(int module_number)
{
REGISTER_LONG_CONSTANT("INPUT_POST", PARSE_POST, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("INPUT_GET", PARSE_GET, CONST_CS | CONST_PERSISTENT);

View file

@ -280,7 +280,7 @@ static const zend_function_entry class_FTP_Connection_methods[] = {
ZEND_FE_END
};
static void register_ftp_consts(int module_number)
static void register_ftp_symbols(int module_number)
{
REGISTER_LONG_CONSTANT("FTP_ASCII", FTPTYPE_ASCII, CONST_CS | CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("FTP_TEXT", FTPTYPE_ASCII, CONST_CS | CONST_PERSISTENT);

View file

@ -118,7 +118,7 @@ PHP_MINIT_FUNCTION(ftp)
ftp_object_handlers.free_obj = ftp_object_destroy;
ftp_object_handlers.clone_obj = NULL;
register_ftp_consts(module_number);
register_ftp_symbols(module_number);
return SUCCESS;
}

View file

@ -1631,7 +1631,7 @@ PHP_MINIT_FUNCTION(hash)
PHP_HASH_HAVAL_REGISTER(5,224);
PHP_HASH_HAVAL_REGISTER(5,256);
register_hash_consts(module_number);
register_hash_symbols(module_number);
php_hashcontext_ce = register_class_HashContext();
php_hashcontext_ce->create_object = php_hashcontext_create;

View file

@ -210,7 +210,7 @@ static const zend_function_entry class_HashContext_methods[] = {
ZEND_FE_END
};
static void register_hash_consts(int module_number)
static void register_hash_symbols(int module_number)
{
REGISTER_LONG_CONSTANT("HASH_HMAC", PHP_HASH_HMAC, CONST_CS | CONST_PERSISTENT);
}

View file

@ -32,6 +32,7 @@
#include "zend_exceptions.h"
#include "ext/spl/spl_exceptions.h"
#include "zend_interfaces.h"
#include "zend_attributes.h"
#include "mysqli_arginfo.h"
ZEND_DECLARE_MODULE_GLOBALS(mysqli)
@ -692,6 +693,8 @@ PHP_MINIT_FUNCTION(mysqli)
REGISTER_BOOL_CONSTANT("MYSQLI_IS_MARIADB", 0, CONST_CS | CONST_PERSISTENT);
#endif
register_mysqli_symbols(module_number, mysqli_link_class_entry);
mysqlnd_reverse_api_register_api(&mysqli_reverse_api);
return SUCCESS;

View file

@ -126,6 +126,7 @@ class mysqli
*/
public int $warning_count;
/** @sensitive-param $password */
public function __construct(
?string $hostname = null,
?string $username = null,

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: a2f2992afd959a13215bfdfd00096f368b3bc392 */
* Stub hash: 794efd97f6eac5e755bed2eb6219173a1ee45321 */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_mysqli_affected_rows, 0, 1, MAY_BE_LONG|MAY_BE_STRING)
ZEND_ARG_OBJ_INFO(0, mysql, mysqli, 0)
@ -1025,6 +1025,11 @@ static const zend_function_entry class_mysqli_sql_exception_methods[] = {
ZEND_FE_END
};
static void register_mysqli_symbols(int module_number, zend_class_entry *class_entry_mysqli)
{
zend_mark_function_parameter_as_sensitive(&class_entry_mysqli->function_table, "__construct", 2);
}
static zend_class_entry *register_class_mysqli_driver(void)
{
zend_class_entry ce, *class_entry;

View file

@ -29,6 +29,7 @@
#include "ext/standard/info.h"
#include "ext/session/php_session.h"
#include "zend_exceptions.h"
#include "zend_attributes.h"
#include "zend_operators.h"
#include "ext/standard/php_dns.h"
#include "ext/standard/php_uuencode.h"
@ -292,7 +293,7 @@ PHP_MINIT_FUNCTION(basic) /* {{{ */
# endif
#endif
register_basic_functions_consts(module_number);
register_basic_functions_symbols(module_number);
php_ce_incomplete_class = register_class___PHP_Incomplete_Class();
php_register_incomplete_class_handlers();

View file

@ -1629,11 +1629,15 @@ function unpack(string $format, string $string, int $offset = 0): array|false {}
*/
function password_get_info(string $hash): array {}
/** @refcount 1 */
/**
* @refcount 1
* @sensitive-param $password
*/
function password_hash(string $password, string|int|null $algo, array $options = []): string {}
function password_needs_rehash(string $hash, string|int|null $algo, array $options = []): bool {}
/** @sensitive-param $password */
function password_verify(string $password, string $hash): bool {}
function password_algos(): array {}

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 29f2ff95da2c07a61f23729da63ada536d2980d1 */
* Stub hash: 0be859a950e082bb02f747630068ea658c6673dd */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0)
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
@ -3515,10 +3515,13 @@ static const zend_function_entry class_AssertionError_methods[] = {
ZEND_FE_END
};
static void register_basic_functions_consts(int module_number)
static void register_basic_functions_symbols(int module_number)
{
REGISTER_DOUBLE_CONSTANT("M_E", M_E, CONST_CS | CONST_PERSISTENT);
ZEND_ASSERT(M_E == 2.7182818284590451);
zend_mark_function_parameter_as_sensitive(CG(function_table), "password_hash", 0);
zend_mark_function_parameter_as_sensitive(CG(function_table), "password_verify", 0);
}
static zend_class_entry *register_class___PHP_Incomplete_Class(void)