Skip to content

Fix GH-15628: php_stream_memory_get_buffer() not zero-terminated #15648

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
wants to merge 3 commits into from

Conversation

cmb69
Copy link
Member

@cmb69 cmb69 commented Aug 29, 2024

We're reasonably sure that appending the NUL is not an OOB write, since the memory stream implementation uses zend_string APIs instead of fiddling with the buffer.

We don't add a regression test because that would require to set up something in the zend_test extension, and regressions are supposed to be caught by external consumers of this API, such as mailparse.

We're reasonably sure that appending the NUL is not an OOB write, since
the memory stream implementation uses `zend_string` APIs instead of
fiddling with the buffer.

We don't add a regression test because that would require to set up
something in the zend_test extension, and regressions are supposed
to be caught by external consumers of this API, such as mailparse.
@cmb69 cmb69 requested a review from bukka as a code owner August 29, 2024 22:37
@cmb69 cmb69 linked an issue Aug 29, 2024 that may be closed by this pull request
@cmb69
Copy link
Member Author

cmb69 commented Aug 30, 2024

Sorry, fix is borked; back to draft.

@cmb69 cmb69 marked this pull request as draft August 30, 2024 14:36
@cmb69
Copy link
Member Author

cmb69 commented Aug 30, 2024

@nielsdos, this requires an additional check for interned strings, and the assumption that these are always zero-terminated. I don't like that hackery, but it might be okay.

@cmb69 cmb69 marked this pull request as ready for review August 30, 2024 16:33
@nielsdos
Copy link
Member

This should probably be fixed in the code where we modify the string, instead of the place where we get the buffer.

This way there are no issues regarding interned strings.
@cmb69
Copy link
Member Author

cmb69 commented Aug 30, 2024

Apparently, there are only two places where we would need to append a trailing NUL (less than I thought). And with this PR, the mailparse issues are gone.

Copy link
Member

@nielsdos nielsdos left a comment

Choose a reason for hiding this comment

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

Perhaps setting the NUL terminator can be moved to the place where the reallocation code is called, but this also works. LGTM

@cmb69
Copy link
Member Author

cmb69 commented Aug 31, 2024

Perhaps setting the NUL terminator can be moved to the place where the reallocation code is called, […]

Supposedly slightly more efficient, but I find doing it after memcpy()/memset() is slightly more intuitive. Let's see what @bukka thinks about this.

@bukka
Copy link
Member

bukka commented Aug 31, 2024

I would prefer to have zend_string API - maybe just some inline function that does memset sets '\0' at the end. I guess we might find more use case for it and seems cleaner to me.

@cmb69
Copy link
Member Author

cmb69 commented Aug 31, 2024

I would prefer to have zend_string API - maybe just some inline function that does memset sets '\0' at the end.

I'm not quite sure what you mean; just something like

static zend_always_inline void zend_string_terminate(zend_string *s)
{
	ZSTR_VAL(s)[ZSTR_LEN(s)] = '\0';
}

I'm not against it, but I don't think we should introduce a new API in a stable branch (note that this targets PHP-8.2).

Comment on lines 243 to +244
memset(ZSTR_VAL(ms->data) + old_size, 0, newsize - old_size);
ZSTR_VAL(ms->data)[ZSTR_LEN(ms->data)] = '\0';
Copy link
Member Author

Choose a reason for hiding this comment

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

This could be simplified

Suggested change
memset(ZSTR_VAL(ms->data) + old_size, 0, newsize - old_size);
ZSTR_VAL(ms->data)[ZSTR_LEN(ms->data)] = '\0';
memset(ZSTR_VAL(ms->data) + old_size, 0, newsize - old_size + 1); // +1 to zero-terminate

@bukka
Copy link
Member

bukka commented Aug 31, 2024

I was initially thinking about having wrappers around memset and memcpy but that doesn't really make much sense. The zend_string_terminate could be an option or maybe we could introduce alternative to zend_string_realloc that would do the termination - e.g. zend_string_realloc_terminated.

I guess it would be probably better to add in master though. I'm fine with this going as a bug fix in the meantime.

@cmb69 cmb69 closed this in 93021c6 Sep 1, 2024
@cmb69 cmb69 deleted the cmb/gh15628 branch September 1, 2024 13:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

php_stream_memory_get_buffer() not zero-terminated
3 participants