Skip to content

Fix GH-17137: Segmentation fault ext/phar/phar.c #17150

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 1 commit into from

Conversation

nielsdos
Copy link
Member

Commit edae243 attempted to fix a leak and double free, but didn't properly understand what was going on, causing a reference count mistake and subsequent segfault in this case.

The first mistake of that commit is that the reference count should've been increased because we're reusing a phar object. The error handling path should've gotten changed instead to undo this refcount increase instead of not refcounting at all (root cause of this bug).

The second mistake is that the alias isn't supposed to be transferred or whatever, that just doesn't make sense. The reason the test bug69958.phpt originally leaked is because in the non-reuse case we borrowed the alias and otherwise we own the alias. If we own the alias the alias information shouldn't get deleted anyway as that would desync the alias map.

Fixing these will reveal a third issue in which the alias memory is not always properly in sync with the persistence-ness of the phar, fix this as well.

@nielsdos nielsdos linked an issue Dec 13, 2024 that may be closed by this pull request
Commit edae243 attempted to fix a leak and double free, but didn't
properly understand what was going on, causing a reference count mistake
and subsequent segfault in this case.

The first mistake of that commit is that the reference count should've
been increased because we're reusing a phar object. The error handling
path should've gotten changed instead to undo this refcount increase
instead of not refcounting at all (root cause of this bug).

The second mistake is that the alias isn't supposed to be transferred or
whatever, that just doesn't make sense. The reason the test
bug69958.phpt originally leaked is because in the non-reuse case we
borrowed the alias and otherwise we own the alias. If we own the alias
the alias information shouldn't get deleted anyway as that would desync
the alias map.

Fixing these will reveal a third issue in which the alias memory is not
always properly in sync with the persistence-ness of the phar, fix this
as well.
@nielsdos
Copy link
Member Author

All these duplications and repeated operations are also quite sad, this code needs some work in master...

@nielsdos nielsdos marked this pull request as ready for review December 13, 2024 21:08
Copy link
Member

@Girgias Girgias left a comment

Choose a reason for hiding this comment

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

Cursory glance, but this makes sense to me.

@nielsdos nielsdos requested a review from cmb69 December 14, 2024 20:07
@nielsdos
Copy link
Member Author

Asking for an additional reviewer, because you know... it's phar after all

Copy link
Member

@cmb69 cmb69 left a comment

Choose a reason for hiding this comment

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

Good analysis! Besides some nits, this looks good to me.

this code needs some work in master

Maybe we should get rid of ZIP and tar support in ext/phar (remove PharData). That adds more complexity, and we already have ext/zip, and the tar implementation is doubtful (I remember a bug report, but can't find, where it turned out that adding a file would rebuilt the whole archive, defeating the idea of tar).

/* NOTE: we know it's not the last reference because the phar is reused. */
phar->refcount--;
}
err_oldpath:
Copy link
Member

Choose a reason for hiding this comment

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

Maybe add a comment that the fallthrough is intentional?

Copy link
Member Author

Choose a reason for hiding this comment

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

I usually don't do this when I write goto-style error-handling code, but perhaps I should. I'll add it here.

var_dump($phar, $phar->decompress());
echo "OK\n";
?>
--EXPECT--
Copy link
Member

Choose a reason for hiding this comment

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

Expecting certain object ID might be too specific; maybe use EXPECTF and %d instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

Fair

pphar->alias = phar->alias; /* Transfer alias to pphar to */
phar->alias = NULL; /* avoid being free'd twice */
/* The alias is not owned by the phar, so set it to NULL to avoid freeing it. */
phar->alias = NULL;
Copy link
Member

Choose a reason for hiding this comment

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

Do we also need phar->alias_len = 0 here?

Copy link
Member Author

Choose a reason for hiding this comment

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

Not necessary because the phar will be freed due to it being the temporary object created by the caller. The free code does not care about alias_len

@nielsdos
Copy link
Member Author

Maybe we should get rid of ZIP and tar support in ext/phar (remove PharData). That adds more complexity, and we already have ext/zip, and the tar implementation is doubtful

Breaks BC most likely.
We fixed some bugs in the zip and tar support already, so it's not as bad as it once was.
Anyway what I was mostly referring to with my comment is how convoluted even the non-tar/zip part is and how many estrdups etc we have instead of using proper zend_strings.

I remember a bug report, but can't find, where it turned out that adding a file would rebuilt the whole archive, defeating the idea of tar

Yeah I also remember something like this, I thought it was related to compression though.

@nielsdos nielsdos closed this in 142f85e Dec 15, 2024
@cmb69
Copy link
Member

cmb69 commented Dec 15, 2024

Breaks BC most likely.

Yeah, would need proper deprecation RFC anyway.

Anyway what I was mostly referring to with my comment is how convoluted even the non-tar/zip part is and how many estrdups etc we have instead of using proper zend_strings.

I concur.

Yeah I also remember something like this, I thought it was related to compression though.

I found https://bugs.php.net/80399 now.

charmitro pushed a commit to wasix-org/php that referenced this pull request Mar 13, 2025
Commit edae243 attempted to fix a leak and double free, but didn't
properly understand what was going on, causing a reference count mistake
and subsequent segfault in this case.

The first mistake of that commit is that the reference count should've
been increased because we're reusing a phar object. The error handling
path should've gotten changed instead to undo this refcount increase
instead of not refcounting at all (root cause of this bug).

The second mistake is that the alias isn't supposed to be transferred or
whatever, that just doesn't make sense. The reason the test
bug69958.phpt originally leaked is because in the non-reuse case we
borrowed the alias and otherwise we own the alias. If we own the alias
the alias information shouldn't get deleted anyway as that would desync
the alias map.

Fixing these will reveal a third issue in which the alias memory is not
always properly in sync with the persistence-ness of the phar, fix this
as well.

Closes phpGH-17150.
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.

Segmentation fault ext/phar/phar.c
3 participants