Skip to content

menu/rgui: convert OSK fallback messagebox build to strlcpy_append #32

menu/rgui: convert OSK fallback messagebox build to strlcpy_append

menu/rgui: convert OSK fallback messagebox build to strlcpy_append #32

name: CI Linux samples/gfx
on:
push:
branches:
- master
pull_request:
branches:
- master
workflow_dispatch:
permissions:
contents: read
env:
ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true
jobs:
samples-gfx:
name: Build and run samples/gfx
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Install dependencies
run: |
sudo apt-get update -y
sudo apt-get install -y build-essential
- name: Checkout
uses: actions/checkout@v3
- name: Build and run vulkan_extension_count_test (ASan)
shell: bash
working-directory: samples/gfx/vulkan_extension_count
run: |
set -eu
# Regression test for the heap-overflow fix in
# gfx/common/vulkan_common.c::vulkan_find_device_extensions.
# Pre-fix the function appended the required-extension list
# twice -- once via memcpy at the top of the body, then
# again in a per-element loop -- consuming
# (count_initial + 2*num_required + num_optional) slots in
# the caller's buffer. vulkan_context_create_device_wrapper
# sized its malloc for (count_initial + num_required +
# num_optional) entries, so a libretro core using the Vulkan
# HW context-negotiation interface against a GPU exposing at
# least one optional extension hit a one-element heap-buffer-
# overflow (8 bytes on 64-bit) at the end of the malloc'd
# block. Build under AddressSanitizer so any reintroduction
# of the duplicate write is caught at the bounds level. If
# vulkan_common.c amends the append-to-enabled[] block, the
# verbatim copy in vulkan_extension_count_test.c must follow.
make clean all SANITIZER=address
test -x vulkan_extension_count_test
timeout 60 ./vulkan_extension_count_test
echo "[pass] vulkan_extension_count_test"
- name: Build and run vulkan_swapchain_clamp_test (ASan)
shell: bash
working-directory: samples/gfx/vulkan_swapchain_clamp
run: |
set -eu
# Regression test for the unclamped-swapchain-image-count
# fix in gfx/common/vulkan_common.c::vulkan_create_swapchain.
# Pre-fix the two vkGetSwapchainImagesKHR calls (count
# query + image fill) had no clamp between them, so a driver
# returning more than VULKAN_MAX_SWAPCHAIN_IMAGES (8) images
# on the second call wrote past context.swapchain_images[8]
# and every loop bounded by num_swapchain_images walked past
# its compile-time-sized companion array (~12 such loops
# across init/deinit/textures/buffers/descriptor pools/
# command buffers/readback and direct vk->swapchain[i]
# uses). Build under AddressSanitizer so any reintroduction
# of either the request-side or the post-create clamp is
# caught at the bounds level. If vulkan_common.c amends
# the cap or the post-create clamp, the verbatim copies in
# vulkan_swapchain_clamp_test.c must follow.
make clean all SANITIZER=address
test -x vulkan_swapchain_clamp_test
timeout 60 ./vulkan_swapchain_clamp_test
echo "[pass] vulkan_swapchain_clamp_test"
- name: Build and run vulkan_texture_size_test (ASan)
shell: bash
working-directory: samples/gfx/vulkan_texture_size
run: |
set -eu
# Regression test for the 32-bit-overflow fix in
# gfx/drivers/vulkan.c::vulkan_create_texture's staging-
# buffer sizing. Pre-fix the buffer_info.size calculation
# (buffer_width * height) was unsigned*unsigned in 32-bit
# before being widened to VkDeviceSize on assignment. With
# dimensions large enough to wrap (e.g. 65536x16385x4 ->
# 0x1_0004_0000 truncates to 0x40000), the staging buffer
# was malloc'd at the wrapped (small) size while the per-row
# upload memcpy loop walked the full width x height,
# writing past the mapped region into adjacent heap memory.
# Reachable from libretro cores supplying oversized
# retro_framebuffer dimensions and from vulkan_load_texture
# / vulkan_set_texture_frame. Build under AddressSanitizer
# so any reintroduction of the 32-bit arithmetic is caught
# at the bounds level. If vulkan.c amends the size
# calculation or upload-loop strides, the verbatim copies
# in vulkan_texture_size_test.c must follow.
make clean all SANITIZER=address
test -x vulkan_texture_size_test
timeout 60 ./vulkan_texture_size_test
echo "[pass] vulkan_texture_size_test"
- name: Build and run slang_texture_index_bounds_test (ASan)
shell: bash
working-directory: samples/gfx/slang_texture_index_bounds
run: |
set -eu
# Regression test for the texture-semantic index-bounds
# fix in gfx/drivers_shader/slang_process.cpp::
# validate_texture_semantic_index(). Pre-fix only
# SLANG_TEXTURE_SEMANTIC_PASS_OUTPUT was bounded against
# reflection->pass_number; ORIGINAL_HISTORY, PASS_FEEDBACK
# and USER had no upper bound on their array index. The
# index suffix in arrayed semantic names like
# `OriginalHistory42` is parsed via strtoul in
# slang_name_to_texture_semantic_array() and propagates
# into the downstream resize_minimum() calls in
# set_ubo_texture_offset() and the direct sampler-binding
# loop. A malicious slang shader declaring
# `OriginalHistory4294967294` makes std::vector::resize
# request ~128 GiB, throwing std::bad_alloc which
# propagates unhandled out of the filter-chain create
# path, terminating the process. Reachable from any
# malicious slang preset (downloaded via Online Updater
# or shipped third-party). Build under AddressSanitizer
# so any reintroduction is caught at the bounds level.
# If slang_process.cpp amends the cap table or the
# dispatch structure, the verbatim copy in
# slang_texture_index_bounds_test.c must follow.
make clean all SANITIZER=address
test -x slang_texture_index_bounds_test
timeout 60 ./slang_texture_index_bounds_test
echo "[pass] slang_texture_index_bounds_test"
- name: Build and run vulkan_mailbox_init_leak_test (ASan + LSan)
shell: bash
working-directory: samples/gfx/vulkan_mailbox_init_leak
run: |
set -eu
# Regression test for the partial-init leak fix in
# gfx/common/vulkan_common.c::vulkan_emulated_mailbox_init.
# Pre-fix the function had three sequential allocations
# (scond_new, slock_new, sthread_create) and on any of the
# latter two failures returned `false` directly, leaking
# the already-allocated cond and/or lock. Both production
# call sites in vulkan_create_swapchain ignore the return
# value, so an init failure also left vk->mailbox.lock ==
# NULL and vk->mailbox.cond == NULL while VK_DATA_FLAG_
# EMULATING_MAILBOX was still set, setting up a NULL-deref
# the next time vulkan_acquire_next_image routed into
# vulkan_emulated_mailbox_acquire_next_image (slock_lock
# on a NULL pointer). Fix routes every early failure
# through `goto error` to a single deinit call, which is
# null-safe and ends with a memset, leaving the struct in
# the same shape the deinit-on-shutdown path produces and
# tripping the existing `mailbox.swapchain == VK_NULL_
# HANDLE` guard at vulkan_acquire_next_image. Build under
# AddressSanitizer with leak detection so any
# reintroduction is caught at the leak level. If
# vulkan_common.c amends the init or deinit, the verbatim
# copies in vulkan_mailbox_init_leak_test.c must follow.
make clean all SANITIZER=address
test -x vulkan_mailbox_init_leak_test
ASAN_OPTIONS=detect_leaks=1 timeout 60 \
./vulkan_mailbox_init_leak_test
echo "[pass] vulkan_mailbox_init_leak_test"
- name: Build and run vulkan_ctx_double_free_test (ASan)
shell: bash
working-directory: samples/gfx/vulkan_ctx_double_free
run: |
set -eu
# Regression test for the double-free / use-after-free
# fix in the Vulkan context drivers' set_video_mode error
# paths: gfx/drivers_context/wayland_vk_ctx.c,
# w_vk_ctx.c, x_vk_ctx.c. Pre-fix each set_video_mode
# called its own destroy()/destroy_resources()+free() on
# ctx_data before returning false; the caller in
# gfx/drivers/vulkan.c::vulkan_init then ran
# vulkan_free()->ctx_driver->destroy(ctx_data) on the
# already-freed pointer (UAF read of struct fields, then
# a second free of the same allocation). Reachable from
# vulkan_surface_create() failure (missing extension /
# driver issue), Wayland's set_video_mode_common_*
# helpers failing, X11's XGetVisualInfo returning NULL,
# or win32_set_video_mode failing. Cocoa (cocoa_vk_ctx)
# and Android (android_vk_ctx) already handle this
# correctly by returning false without freeing -- the
# fix makes Wayland/Win32/X11 match. Build under
# AddressSanitizer so any reintroduction is caught at
# the bounds level (UAF + double-free both fire). If
# any of the three context drivers amends the
# set_video_mode error path to once again destroy
# ctx_data, the verbatim copy in
# vulkan_ctx_double_free_test.c must follow.
make clean all SANITIZER=address
test -x vulkan_ctx_double_free_test
timeout 60 ./vulkan_ctx_double_free_test
echo "[pass] vulkan_ctx_double_free_test"