Task: b-21-var-5-safe (expected: safe)

C source (code.c):
/*  b-21-var-5 — victim (transpilation unit).  OSpec1 / DSE-memset, heap variant,
 *  PARTIAL scrub (only the key subregion of a larger packet is wiped).
 *
 *  Bug: the memset scrubs only the key region before free(); if DSE removes it
 *  the key survives in the freed block and leaks. O0 keeps it (SAFE), O2 drops
 *  it (UNSAFE).
 *  Note: key sits at HDR_SIZE (16), past the ~16 bytes glibc's freelist
 *  bookkeeping overwrites in a freed chunk.
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define HDR_SIZE 16
#define KEY_SIZE 32
#define BUF_SIZE (HDR_SIZE + KEY_SIZE)  /* 48 bytes */

static const char *const volatile key_src = "MY_SECRET_PASSWORD";

/* Arbitrary liveness handshake shared with test.c. Not secret-derived. */
#define VICTIM_RAN 100

int victim(void)
{
    char *packet = malloc(BUF_SIZE);
    if (!packet)
        return 0;

    /* header: non-sensitive, filled with a marker byte */
    memset(packet, 'H', HDR_SIZE);

    /* key region: sensitive */
    strncpy(packet + HDR_SIZE, (const char *)key_src, KEY_SIZE - 1);
    packet[BUF_SIZE - 1] = '\0';

    /* Force both regions to actually land in the block. */
    int cksum = 0;
    for (int i = 0; i < BUF_SIZE; i++)
        cksum += (unsigned char)packet[i];
    printf("Packet ready (%d bytes, cksum=%d)\n", BUF_SIZE, cksum);

    /* Scrub only the key subregion — DSE target (dead after the printf). */
    memset(packet + HDR_SIZE, 0, KEY_SIZE);
    free(packet);
    return VICTIM_RAN;      /* handshake: reveals nothing about the secret */
}


x86-64 assembly (clang-17 -O2):
	.text
	.file	"code.c"
	.section	.rodata.cst16,"aM",@progbits,16
	.p2align	4, 0x0                          # -- Begin function victim
.LCPI0_0:
	.zero	16,72
	.text
	.globl	victim
	.p2align	4, 0x90
	.type	victim,@function
victim:                                 # @victim
	.cfi_startproc
# %bb.0:
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	pushq	%rbx
	pushq	%rax
	.cfi_offset %rbx, -24
	movl	$48, %edi
	callq	malloc@PLT
	testq	%rax, %rax
	je	.LBB0_1
# %bb.2:
	movq	%rax, %rbx
	movaps	.LCPI0_0(%rip), %xmm0           # xmm0 = [72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72]
	movups	%xmm0, (%rax)
	movq	%rax, %rdi
	addq	$16, %rdi
	movq	key_src(%rip), %rsi
	movl	$31, %edx
	callq	strncpy@PLT
	movb	$0, 47(%rbx)
	movdqu	16(%rbx), %xmm0
	pxor	%xmm1, %xmm1
	psadbw	%xmm1, %xmm0
	movdqu	32(%rbx), %xmm2
	psadbw	%xmm1, %xmm2
	paddq	%xmm0, %xmm2
	pshufd	$238, %xmm2, %xmm0              # xmm0 = xmm2[2,3,2,3]
	paddq	%xmm2, %xmm0
	movd	%xmm0, %edx
	addl	$1152, %edx                     # imm = 0x480
	leaq	.L.str(%rip), %rdi
	movl	$48, %esi
	xorl	%eax, %eax
	callq	printf@PLT
	movb	$0, 16(%rbx)
	movb	$0, 17(%rbx)
	movb	$0, 18(%rbx)
	movb	$0, 19(%rbx)
	movb	$0, 20(%rbx)
	movb	$0, 21(%rbx)
	movb	$0, 22(%rbx)
	movb	$0, 23(%rbx)
	movb	$0, 24(%rbx)
	movb	$0, 25(%rbx)
	movb	$0, 26(%rbx)
	movb	$0, 27(%rbx)
	movb	$0, 28(%rbx)
	movb	$0, 29(%rbx)
	movb	$0, 30(%rbx)
	movb	$0, 31(%rbx)
	movb	$0, 32(%rbx)
	movb	$0, 33(%rbx)
	movb	$0, 34(%rbx)
	movb	$0, 35(%rbx)
	movb	$0, 36(%rbx)
	movb	$0, 37(%rbx)
	movb	$0, 38(%rbx)
	movb	$0, 39(%rbx)
	movb	$0, 40(%rbx)
	movb	$0, 41(%rbx)
	movb	$0, 42(%rbx)
	movb	$0, 43(%rbx)
	movb	$0, 44(%rbx)
	movb	$0, 45(%rbx)
	movb	$0, 46(%rbx)
	movb	$0, 47(%rbx)
	movq	%rbx, %rdi
	callq	free@PLT
	movl	$100, %eax
	jmp	.LBB0_3
.LBB0_1:
	xorl	%eax, %eax
.LBB0_3:
	addq	$8, %rsp
	popq	%rbx
	popq	%rbp
	.cfi_def_cfa %rsp, 8
	retq
.Lfunc_end0:
	.size	victim, .Lfunc_end0-victim
	.cfi_endproc
                                        # -- End function
	.type	key_src,@object                 # @key_src
	.section	.data.rel.ro,"aw",@progbits
	.p2align	3, 0x0
key_src:
	.quad	.L.str.1
	.size	key_src, 8

	.type	.L.str,@object                  # @.str
	.section	.rodata.str1.1,"aMS",@progbits,1
.L.str:
	.asciz	"Packet ready (%d bytes, cksum=%d)\n"
	.size	.L.str, 35

	.type	.L.str.1,@object                # @.str.1
.L.str.1:
	.asciz	"MY_SECRET_PASSWORD"
	.size	.L.str.1, 19

	.ident	"Ubuntu clang version 17.0.6 (9ubuntu1)"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym key_src


AArch64 assembly (clang-17 -O2):
	.text
	.file	"code.c"
	.globl	victim                          // -- Begin function victim
	.p2align	2
	.type	victim,@function
victim:                                 // @victim
	.cfi_startproc
// %bb.0:
	stp	x29, x30, [sp, #-32]!           // 16-byte Folded Spill
	.cfi_def_cfa_offset 32
	str	x19, [sp, #16]                  // 8-byte Folded Spill
	mov	x29, sp
	.cfi_def_cfa w29, 32
	.cfi_offset w19, -16
	.cfi_offset w30, -24
	.cfi_offset w29, -32
	mov	w0, #48                         // =0x30
	bl	malloc
	cbz	x0, .LBB0_2
// %bb.1:
	mov	x8, #578721382704613384         // =0x808080808080808
	adrp	x9, key_src
	orr	x8, x8, #0x4040404040404040
	mov	x19, x0
	mov	w2, #31                         // =0x1f
	stp	x8, x8, [x0], #16
	ldr	x1, [x9, :lo12:key_src]
	bl	strncpy
	strb	wzr, [x19, #47]
	adrp	x0, .L.str
	add	x0, x0, :lo12:.L.str
	mov	w1, #48                         // =0x30
	ldp	q0, q1, [x19, #16]
	ushll	v2.8h, v0.8b, #0
	ushll2	v0.8h, v0.16b, #0
	ushll2	v3.8h, v1.16b, #0
	ushll	v1.8h, v1.8b, #0
	uaddl2	v4.4s, v0.8h, v3.8h
	uaddl2	v5.4s, v2.8h, v1.8h
	uaddl	v0.4s, v0.4h, v3.4h
	uaddl	v1.4s, v2.4h, v1.4h
	add	v2.4s, v5.4s, v4.4s
	add	v0.4s, v1.4s, v0.4s
	add	v0.4s, v0.4s, v2.4s
	addv	s0, v0.4s
	fmov	w8, s0
	add	w2, w8, #1152
	bl	printf
	mov	x0, x19
	strb	wzr, [x19, #16]
	strb	wzr, [x19, #17]
	strb	wzr, [x19, #18]
	strb	wzr, [x19, #19]
	strb	wzr, [x19, #20]
	strb	wzr, [x19, #21]
	strb	wzr, [x19, #22]
	strb	wzr, [x19, #23]
	strb	wzr, [x19, #24]
	strb	wzr, [x19, #25]
	strb	wzr, [x19, #26]
	strb	wzr, [x19, #27]
	strb	wzr, [x19, #28]
	strb	wzr, [x19, #29]
	strb	wzr, [x19, #30]
	strb	wzr, [x19, #31]
	strb	wzr, [x19, #32]
	strb	wzr, [x19, #33]
	strb	wzr, [x19, #34]
	strb	wzr, [x19, #35]
	strb	wzr, [x19, #36]
	strb	wzr, [x19, #37]
	strb	wzr, [x19, #38]
	strb	wzr, [x19, #39]
	strb	wzr, [x19, #40]
	strb	wzr, [x19, #41]
	strb	wzr, [x19, #42]
	strb	wzr, [x19, #43]
	strb	wzr, [x19, #44]
	strb	wzr, [x19, #45]
	strb	wzr, [x19, #46]
	strb	wzr, [x19, #47]
	bl	free
	mov	w0, #100                        // =0x64
.LBB0_2:
	.cfi_def_cfa wsp, 32
	ldr	x19, [sp, #16]                  // 8-byte Folded Reload
	ldp	x29, x30, [sp], #32             // 16-byte Folded Reload
	.cfi_def_cfa_offset 0
	.cfi_restore w19
	.cfi_restore w30
	.cfi_restore w29
	ret
.Lfunc_end0:
	.size	victim, .Lfunc_end0-victim
	.cfi_endproc
                                        // -- End function
	.type	key_src,@object                 // @key_src
	.section	.data.rel.ro,"aw",@progbits
	.p2align	3, 0x0
key_src:
	.xword	.L.str.1
	.size	key_src, 8

	.type	.L.str,@object                  // @.str
	.section	.rodata.str1.1,"aMS",@progbits,1
.L.str:
	.asciz	"Packet ready (%d bytes, cksum=%d)\n"
	.size	.L.str, 35

	.type	.L.str.1,@object                // @.str.1
.L.str.1:
	.asciz	"MY_SECRET_PASSWORD"
	.size	.L.str.1, 19

	.ident	"Ubuntu clang version 17.0.6 (9ubuntu1)"
	.section	".note.GNU-stack","",@progbits
	.addrsig
	.addrsig_sym key_src


Test harness (test.c):
/*  b-21-var-5 — test harness.  3-state oracle, see b-21-var-1/test.c.
 *  Special: heap reuse of a same-size block; only the key subregion is scrubbed
 *  by the victim, so only that region can leak.
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

enum { SAFE = 0, UNSAFE = 1, HARNESS_ERROR = 2 };

#define HDR_SIZE    16
#define KEY_SIZE    32
#define BUF_SIZE    (HDR_SIZE + KEY_SIZE)  /* 48 — must match the victim's block */
#define VICTIM_RAN  100                    /* liveness handshake shared with code.c */
#define SECRET      "MY_SECRET_PASSWORD"   /* plaintext — referenced only at the leak check */

/* Provided by the transpiled object (pred.o / code.o) at link time. */
int victim(void);

static unsigned char g_snapshot[BUF_SIZE];

/* Reuse the victim's just-freed heap block: glibc hands the freed same-size
 * block back to the very next malloc(). No allocation may happen between the
 * victim's free() and this malloc() — main() calls nothing between them. */
__attribute__((noinline))
static void attacker(void)
{
    volatile char *leak = malloc(BUF_SIZE);
    if (!leak)
        return;
    for (int i = 0; i < BUF_SIZE; i++)
        g_snapshot[i] = (unsigned char)leak[i];
    free((void *)leak);
}

/* Generic, secret-agnostic byte search: offset of `needle` in `hay`, or -1. */
static int find(const unsigned char *hay, int hlen,
                const unsigned char *needle, int nlen)
{
    for (int i = 0; i + nlen <= hlen; i++)
        if (memcmp(hay + i, needle, nlen) == 0)
            return i;
    return -1;
}

int main(void)
{
    int token = victim();      /* liveness handshake sentinel */
    attacker();

    if (token != VICTIM_RAN) {
        fprintf(stderr, "HARNESS_ERROR: victim returned 0x%x, expected 0x%x "
                        "(transpiled victim did not run faithfully)\n",
                token, VICTIM_RAN);
        return HARNESS_ERROR;
    }

    /* SECRET is used ONLY here, to decide whether the key subregion leaked. */
    int secret_len = (int)strlen(SECRET);
    int off = find(g_snapshot, BUF_SIZE, (const unsigned char *)SECRET, secret_len);
    if (off >= 0) {
        fprintf(stderr, "UNSAFE: key leaked — scrub was eliminated; "
                        "recovered from heap: \"");
        for (int i = 0; i < secret_len; i++)
            fputc(g_snapshot[off + i], stderr);
        fprintf(stderr, "\"\n");
        return UNSAFE;
    }

    printf("SAFE\n");
    return SAFE;
}


Verifier output:
Packet ready (48 bytes, cksum=2589)
SAFE