swipl-devel icon indicating copy to clipboard operation
swipl-devel copied to clipboard

Running strip on standalone binary removes save state

Open xelxebar opened this issue 5 months ago • 2 comments

Overview

Running GNU binutils strip on a qsave_program/2 standalone ELF binary removes the save state data, resulting in a binary that just drops to a dry swipl REPL, i.e.

$ prog        # Works
$ strip prog  # This should be harmless, right?
$ prog        # Now broken

The standalone binary doesn't contain debug symbols in the first place, so arguably the correct action is to just not use strip in the first place. However, there is at least one previous report on the forums, and in my case, strip is automatically run by a distribution package builder, causing very confusing breakages.

Analysis

The issue is that strip removes any data in an ELF not referenced by an ELF section, and qsave_program/2 produces a Zip archive concatenated to an ELF stub, meaning that the trailing Zip data remains anonymous:

$ binwalk prog

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ELF, 64-bit LSB executable, AMD x86-64, version 1 (SYSV)
294522        0x47E7A         End of Zip archive, footer length: 22

but

$ cp prog prog.stripped
$ strip prog.stripped
$ cmp prog prog.stripped
cmp: EOF on plwm.stripped after byte 14392, in line 2
$ binwalk prog.stripped

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
0             0x0             ELF, 64-bit LSB executable, AMD x86-64, version 1 (SYSV)

This show that strip was a no-op on the ELF stub but removed everything after byte 14392 = 0x3838.

Proof of Concept Fix

The idea for mitigation is simple: just create an ELF section that references the Zip archive data. Below is a manual demonstration of the idea that I have confirmed works:

$ unzip a.out; zip -Dr '$prolog' a.zip     # Extract the zip archive
$ strip a.out; mv a.out a.stub             # Extract the ELF stub
$ objcopy --add-section .zipdata=a.zip --set-section-flags .zipdata=readonly,data a.stub plwm

Is it reasonable to patch qsave_program/2, or wherever relevant, to add such an ELF section? Other thoughts?

xelxebar avatar May 30 '25 00:05 xelxebar