ASAN behaviour on snap

Hey, we want to run address sanitizers on Snap to inspect bugs/leaks etc.

I do get some behaviours on running asan in snap. It aborts the program on the first report instead of full reports, while the same app does not abort on the host with the same settings ASAN_OPTIONS=halt_on_error=0 and libasan/glibc.

For replicating it, I have made a simple C++ app.

Any input would be great.

main.cpp

#include <chrono>
#include <iostream>
#include <thread>

void do_some_work(const char* phase, int steps, int delay_ms) {
    std::cout << "[" << phase << "] starting..." << std::endl;
    for (int i = 1; i <= steps; ++i) {
        std::cout << "[" << phase << "] step " << i << "/" << steps << std::endl;
        std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
    }
    std::cout << "[" << phase << "] done." << std::endl;
}

__attribute__((noinline)) void trigger_asan_error() {
    std::cout << "\nTriggering ASan bug: heap-buffer-overflow..." << std::endl;

    int* data = new int[4]{10, 20, 30, 40};

    // Runtime index avoids constant-folding and forces a real memory access.
    const auto now = std::chrono::steady_clock::now().time_since_epoch().count();
    const int bad_index = 8 + static_cast<int>(now & 1);

    // Intentional bug: out-of-bounds read (ASan should report this).
    volatile int value = data[bad_index];
    std::cout << "Read out-of-bounds value: " << value << std::endl;

    delete[] data;
}

int main() {
    std::cout << "Program started.\n" << std::endl;

    do_some_work("pre-bug work", 3, 350);
    trigger_asan_error();
    do_some_work("post-bug work", 3, 350);

    std::cout << "\nProgram finished." << std::endl;
    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(asan_demo LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

add_executable(asan_demo main.cpp)

# Build with AddressSanitizer and recovery so the program can continue
# after reporting an error (with ASAN_OPTIONS=halt_on_error=0).
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
    target_compile_options(asan_demo PRIVATE
        -g
        -O1
        -fno-omit-frame-pointer
        -fsanitize=address
        -fsanitize-recover=address
    )
    target_link_options(asan_demo PRIVATE
        -fsanitize=address
        -fsanitize-recover=address
    )
endif()

install(TARGETS asan_demo RUNTIME DESTINATION bin)

snapcraft.yaml

name: asan-demo
base: core24
version: "0.1.0"
summary: C++ AddressSanitizer demo
description: |
  A small C++ app that intentionally triggers an AddressSanitizer error,
  then continues running to perform additional work.

grade: devel
confinement: strict

apps:
  asan-demo:
    command: usr/bin/asan_demo
    environment:
      ASAN_OPTIONS: halt_on_error=0:abort_on_error=0

parts:
  asan-demo:
    plugin: cmake
    source: .
    cmake-parameters:
      - -DCMAKE_BUILD_TYPE=RelWithDebInfo
      - -DCMAKE_INSTALL_PREFIX=/usr
    build-packages:
      - g++-13
      - cmake
    stage-packages:
      - libstdc++6
      - libasan8

Hey @ogra in case you have some input, or can tag relevant people.

Also a note, i have checked my host and snap have same version of libasan. My wild guess something is blocking on snap confinement.

Well, the snapd team (@mborzecki1 perhaps ?) would likely be better suited to answer any detailed questions here (they also cared for getting strace and gdb working inside snaps so there should be some prior knowledge around debugger tools), but in general did you run snappy-debug aside your test to see if there are any apparmor/seccomp limitations blocking you ?

Only thing i got from snappy-debug is , not sure its helpful


= AppArmor =
Time: Apr 30 14:10:42
Log: apparmor="DENIED" operation="open" class="file" profile="snap.asan-demo.asan-demo" name="/proc/784929/environ" pid=784929 comm="asan_demo" requested_mask="r" denied_mask="r" fsuid=1000 ouid=1000
File: /proc/784929/environ (read)
Suggestion:
* adjust program to not access '@{PROC}/@{pid}/environ'

What i did is installing snap with –devmode , now i can get all asan report without app being aborted.

Do you guys see if –devmode can hide anything compared to –strict mode. What i am concerned in case we use it with devmode will it cover all Adress errors.