Skip to content

[0.4.x] libvisual: Fix palette use-after-free (when switching actors) - #214

Merged
hartwork merged 4 commits into
0.4.xfrom
0.4.x-fix-palette-use-after-free
Feb 13, 2023
Merged

hartwork merged 4 commits into
0.4.xfrom
0.4.x-fix-palette-use-after-free

Conversation

@hartwork

Copy link
Copy Markdown
Member

Can be reproduced by running lv-tool --exclude projectM,gforce --switch 10 with AddressSanitizer active.

visual_log (VISUAL_LOG_DEBUG, "Entering...");
if (bin->managed == TRUE)
visual_object_unref (VISUAL_OBJECT (bin->actor));
visual_video_set_palette (bin->actvideo, NULL);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@hartwork, where does the use-after-free happen? This also seems like an odd place to reset the palette. I feel that there should be a better place to stick this line in.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@kaixiong what I observed was that the palette of one plug-in would be used by the next one, because nothing was resetting the video palette on actor cleanup (where the free is happening) and then the first time that update_all runs in lv-tool, the new plugin has not been asked for its palette yet. While writing that, maybe we need changes in two places: avoiding the stale palette pointer but also getting a fresh one in before the first render. I'm happy to put these wherever fits best. What do you think?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@hartwork That sounds like a good approach. I'm wondering how much work that is though.

If that's a lot of effort, I'm okay with fixing it like this (it's a critical bug after all) but with a big FIXME comment added above it so it can be re-looked at later.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@kaixiong I went a bit further with this, let me know how you like the new version.

@hartwork
hartwork force-pushed the 0.4.x-fix-palette-use-after-free branch 2 times, most recently from af437e5 to 55b7a2e Compare January 28, 2023 03:23
@hartwork
hartwork requested a review from kaixiong January 28, 2023 03:25
@hartwork
hartwork force-pushed the 0.4.x-fix-palette-use-after-free branch 5 times, most recently from 9f7dc89 to 73ac23b Compare January 30, 2023 20:42
Comment thread libvisual/tools/lv-tool/lv-tool.cpp Outdated
: std::min(target_colors, static_cast<visual_size_t>(pal->ncolors));
std::array<SDL_Color, target_colors> colors {};
for (visual_size_t i = 0; i < source_colors; i++) {
colors[i].r = pal->colors[i].r;

@kaixiong kaixiong Jan 30, 2023 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@hartwork hmm.. I'm not sure I understand why this fixes the reported use-after-free.

On the change itself:

The entire 256-entry palette should be set, so if the source palette is smaller than that, the remaining entries should be assigned black. This is the original behaviour and #215 was where it was pointed out. Unfortunately, #213 was already applied and now 0.4 has the altered behaviour.

The other thing is that I'd prefer to use std::size_t instead of visual_size_t.

Finally, I think target_ncolors or target_color_count is better than 'target_colors`, a name that tends to suggest colour values, rather than a count of them.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@hartwork hmm.. I'm not sure I understand why this fixes the reported use-after-free.

@kaixiong thanks for the review! Strictly speaking, there are three (related) things going on in here:

  • Set the pointer to NULL that lived longer than it should have. That technically fixes the use-after-free already.
  • The second things is that not only do we need to get rid of the old palette, we also need to get in the new applied. There was a code path where that didn't happen, previously. That fix is the second part.
  • The third part is improving the upload of the palette to SDL, more on that below.

On the change itself:

The entire 256-entry palette should be set

Ack!

, so if the source palette is smaller than that, the remaining entries should be assigned black.

Ack!

This is the original behaviour

Not on 0.4.x, it copies full 256 entries or nothing at the moment:

for (int i = 0; i < 256; i++) {
colors[i].r = pal->colors[i].r;
colors[i].g = pal->colors[i].g;
colors[i].b = pal->colors[i].b;
}

and #215 was where it was pointed out.

Yes, but that was master and we didn't apply it because it was mistaken and you caught it during review 👍

Unfortunately, #213 was already applied and now 0.4 has the altered behaviour.

Pull request #213 fixed out-of-bounds access but did not change behavior beyond that. Now pull request #214 right here tries to get it right.

The other thing is that I'd prefer to use std::size_t instead of visual_size_t.

Can do, give me a minute.

Finally, I think target_ncolors or target_color_count is better than 'target_colors`, a name that tends to suggest colour values, rather than a count of them.

Ack, will adjust in a minute.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

The other thing is that I'd prefer to use std::size_t instead of visual_size_t.

Can do, give me a minute.

Finally, I think target_ncolors or target_color_count is better than 'target_colors`, a name that tends to suggest colour values, rather than a count of them.

Ack, will adjust in a minute.

@kaixiong done

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@hartwork Thanks. I have another suggestion. Instead of having that complicated looking std::min() expression with a ternary operator, why not use an if block?

std::array<SDL_Color, 256> colors {};
if (pal) {
    const std::size_t pal_color_count = std::min(colors.size(), static_cast<visual_size_t>(pal->ncolors));
    
    for (std::size_t i = 0; i < pal_color_count; i++) {
        colors[i].r = pal->colors[i].r;
        colors[i].g = pal->colors[i].g;
        colors[i].b = pal->colors[i].b;
    }
}
SDL_SetColors (m_screen, colors.data(), 0, colors.size());

@hartwork hartwork Feb 5, 2023 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@kaixiong that's a nice idea, done

@hartwork
hartwork force-pushed the 0.4.x-fix-palette-use-after-free branch 2 times, most recently from fed5592 to 4dfd5af Compare February 1, 2023 16:45
@hartwork

hartwork commented Feb 1, 2023

Copy link
Copy Markdown
Member Author

@kaixiong the Clang 16 CI issues here will go away after rebasing onto a merged #231.

@hartwork
hartwork force-pushed the 0.4.x-fix-palette-use-after-free branch 3 times, most recently from 316408f to 5ccb250 Compare February 2, 2023 20:15
@hartwork
hartwork force-pushed the 0.4.x-fix-palette-use-after-free branch 3 times, most recently from 17bf096 to 04bbd77 Compare February 4, 2023 01:45
@hartwork hartwork changed the title [0.4.x] libvisual: Fix palette use after free (when switching actors) [0.4.x] libvisual: Fix palette use-after-free (when switching actors) Feb 4, 2023
@hartwork
hartwork force-pushed the 0.4.x-fix-palette-use-after-free branch from 04bbd77 to f1a1588 Compare February 5, 2023 17:02
@hartwork
hartwork requested a review from kaixiong February 5, 2023 17:03
@hartwork
hartwork force-pushed the 0.4.x-fix-palette-use-after-free branch from f1a1588 to 981b9a2 Compare February 6, 2023 02:03
@kaixiong

kaixiong commented Feb 6, 2023

Copy link
Copy Markdown
Member

@hartwork, sorry for the delay. Let me review the use-after-free fix soon.

@hartwork

hartwork commented Feb 6, 2023

Copy link
Copy Markdown
Member Author

@hartwork, sorry for the delay. Let me review the use-after-free fix soon.

@kaixiong thank you! 👍

@hartwork

Copy link
Copy Markdown
Member Author

@kaixiong do we need any more improvements here before a merge?

@kaixiong

kaixiong commented Feb 13, 2023 •

Copy link
Copy Markdown
Member

@kaixiong do we need any more improvements here before a merge?

@hartwork No it's all good. I was trying to find time to check the use-after-free fix and understand why it works.

@hartwork
hartwork merged commit 392d182 into 0.4.x Feb 13, 2023
@hartwork
hartwork deleted the 0.4.x-fix-palette-use-after-free branch February 13, 2023 16:07
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