Skip to content
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

ext/bcmath: Added fuzzer for divide #18045

Open
wants to merge 10 commits into
base: PHP-8.4
Choose a base branch
from

Conversation

SakiTakamachi
Copy link
Member

@SakiTakamachi SakiTakamachi commented Mar 13, 2025

Since the BCMath code has changed significantly since version 8.4, I thought that if I were to introduce a fuzzer, it would be best to version 8.4 or later.

This is my first time working with fuzzers, so I don't know who to ask for a review...

@SakiTakamachi SakiTakamachi marked this pull request as ready for review March 13, 2025 15:58
@SakiTakamachi SakiTakamachi requested a review from nielsdos March 13, 2025 15:58
zend_long scale = char_to_size_t(scale_str);
free(scale_str);

if (fuzzer_request_startup() == FAILURE) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should happen earlier to not leak memory.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed unnecessary memory allocations and relocated code.
How about the code now?
e1fa2fa

ZVAL_STRINGL(&args[2], divisor_str, divisor_len);
ZVAL_LONG(&args[3], scale);

fuzzer_call_php_func_zval("bcdiv", 4, args);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great to extend the fuzzer to pick one of a few bc function at random (e.g. bcadd, bcsub, ...)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed in bd630e3

ZVAL_UNDEF(&result);

zval args[4];
ZVAL_COPY_VALUE(&args[0], &result);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very confused by this line, fuzzer_call_php_func_zval uses a local zval for the result. You only need to pass 3 arguments as far as I can tell.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5341ef7


int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
/* num1,num2,scale */
const uint8_t *Comma1 = memchr(Data, ',', Size);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please just use snake_case instead of CamelCase for variables

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 1fb2cd1


zend_long char_to_size_t(char *c) {
zend_long ret = 0;
if (*c >= '0' && *c <= '9') {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could also cause overflow

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 82ed67d
Parsing scale was left unfinished code...

return len;
}

size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not so sure a custom mutator is the best approach. You're also not really mutating the buffer here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it be better to let the fuzzer mutate the input but just choose to interpret the raw bytes as numbers?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nielsdos

Thanks, does that mean accepting the mutated input as is? Or does it mean, for example, taking it, chopping it into 64-bit chunks, interpreting them as integers, converting them to numeric characters, and concatenating them?

I had trouble creating numeric data with no decimal points or just one, so I used a custom mutator.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it so that the mutated input is entered as is.
e1fa2fa
13319aa

@SakiTakamachi
Copy link
Member Author

When building with the fuzzer enabled, it was quite troublesome if the generated executable file was under git management, so I listed it in .gitignore.

@SakiTakamachi SakiTakamachi requested a review from nielsdos March 21, 2025 12:11
@SakiTakamachi
Copy link
Member Author

I forgot to fix the README. There are no more additional fixes to be made.

sprintf(func_name, "%s", "bcmod");
break;
case 5:
sprintf(func_name, "%s", "bcpow");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the exponent is large, the processing is too slow. It may be better to set a limit such as "when num2 is less than 1000"...

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

Successfully merging this pull request may close these issues.

2 participants