Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

launderattack source pure

Package launderattack imports launderpkg and provides functions that attempt to mutate a /p/-typed value passed by po...

Overview

Package launderattack imports launderpkg and provides functions that attempt to mutate a /p/-typed value passed by pointer. This is the "/p/attack imports /p/orig" variation: the goal is for code declared in this /p/ package to mutate a /r/-victim's instance of launderpkg.Object.

Variables 1

var StoredHook

1var StoredHook = func(o *launderpkg.Object) {
2	o.Field = "pwnd-via-stored-closure"
3}
source

StoredHook is a /p/attack package-level closure: a FuncLit evaluated during /p/launderattack init, so its ObjectInfo.PkgID is stamped /p/launderattack. Unlike a top-level FuncDecl (EvilWrite/EvilObjectWrite, IsClosure=false), invoking a closure triggers PushFrameCall's borrow rule #3, which borrows m.Realm to the closure's construction realm (/p/launderattack). Used to probe rule #3: a write through it to a foreign /r/ object must still be rejected. (If rule #3 ever regressed to a nil borrow, m.Realm would go nil and the write would silently succeed.)

Functions 5

func EvilObjectWrite

1func EvilObjectWrite(o *launderpkg.Object)
source

EvilObjectWrite is the same shape but for *Object — used by tests that exercise Object's mutator surface through Apply-style callbacks.

func EvilWrite

1func EvilWrite(i *launderpkg.Immutable)
source

EvilWrite is a top-level /p/-declared function value matching `func(*launderpkg.Immutable)`. Top-level /p/ functions trigger neither borrow rule #1 (not /r/-declared) nor borrow rule #2 (no receiver), so when EvilWrite is invoked as a callback from inside a borrowed-to-victim /p/-method body (e.g. Immutable.Apply, or any avl.Tree.Iterate-style hook), it inherits the victim's m.Realm and the write commits under victim authority.

func TamperDirect

1func TamperDirect(o *launderpkg.Object, s string)
source

TamperDirect writes through the pointer in its own body. The body runs under whatever m.Realm the caller had at PushFrameCall — for a top-level /p/ function with no receiver, that's the caller's realm. If the caller is attacker-realm, m.Realm at the write is attacker-realm and the readonly check fires on a foreign-stamped base.

func TamperViaMethod

1func TamperViaMethod(o *launderpkg.Object, s string)
source

TamperViaMethod dispatches through the launderpkg.Object's own /p/ method. PushFrameCall for Set sees a receiver stamped with the victim's realm (the pointer aliases victim's persisted state), triggering borrow rule 2: m.Realm becomes victim for the duration of Set. The write succeeds — but this requires launderpkg.Object to expose a Set method to begin with.

func Convert

1func Convert(p *launderpkg.Immutable) *Tamper
source

Convert is the attacker's helper that does the type punning so the caller doesn't have to write the conversion inline.

Types 9

type EvilAnyMutator

ident
1type EvilAnyMutator int
source

EvilAnyMutator's Run takes `any` and type-asserts to *Immutable. The signature reveals NO foreign-/p/-pointer statically — the pointer is hidden inside the interface box. Probes whether the predicate needs to fire on interface-typed params too.

Methods on EvilAnyMutator

func Run

method on EvilAnyMutator
1func (EvilAnyMutator) Run(x any)
source

type EvilFunc

func
1type EvilFunc func()
source

EvilFunc / EvilSlice / EvilMap — additional nil-anchor shapes. nil-valued receivers of defined types whose underlying is a reference type (slice/map/func) also have GetFirstObject == nil. The Attack H/I fix should cover all of them via the recvDeclaredTypePkgPath helper.

Methods on EvilFunc

func Run

method on EvilFunc
1func (EvilFunc) Run(i *launderpkg.Immutable)
source

type EvilMap

map
1type EvilMap map[string]int
source

Methods on EvilMap

func Run

method on EvilMap
1func (EvilMap) Run(i *launderpkg.Immutable)
source

type EvilMutator

ident
1type EvilMutator int
source

EvilMutator implements launderpkg.Mutator with a PRIMITIVE underlying type. Underlying-type matters: a struct/array/etc. receiver has a *StructValue that gets PkgID-stamped at allocation, triggering PushFrameCall's receiver-borrow rule to shift m.Realm back to /p/launderattack. A primitive-underlying type has no *StructValue and no PkgID — `recv.GetFirstObject` returns nil, so the borrow rule's `if obj != nil { ... }` branch is skipped and m.Realm stays at whatever the caller had it set to.

When Run is dispatched via interface from inside a /p/-method body that was receiver-borrowed to the victim, m.Realm at Run's entry is the victim's — and stays the victim's, because EvilMutator (an int underneath) carries no PkgID to borrow against. The write inside Run commits under victim authority.

Methods on EvilMutator

func Run

method on EvilMutator
1func (EvilMutator) Run(i *launderpkg.Immutable)
source

type EvilNilRecv

struct
1type EvilNilRecv struct {
2	X int // unused
3}
source

EvilNilRecv tests the nil-pointer-receiver variant. Calling a method on a nil *EvilNilRecv is legal in Gno when the body doesn't deref the receiver. recv = PointerValue{Base: nil} → GetBase returns nil → GetFirstObject returns nil. Same "no anchor" gap as the primitive-receiver case, reachable through *T receivers.

Methods on EvilNilRecv

func Run

method on EvilNilRecv
1func (n *EvilNilRecv) Run(i *launderpkg.Immutable)
source

type EvilSlice

slice
1type EvilSlice []int
source

Methods on EvilSlice

func Run

method on EvilSlice
1func (EvilSlice) Run(i *launderpkg.Immutable)
source

type EvilSliceMutator

ident
1type EvilSliceMutator int
source

EvilSliceMutator's Run takes a slice — NOT a pointer parameter, so the Attack H/I fix's `hasForeignPPtrParam` predicate skips it. Tests whether the anchor predicate needs to look INSIDE composite parameter types for foreign-/p/ pointers.

Methods on EvilSliceMutator

func Run

method on EvilSliceMutator
1func (EvilSliceMutator) Run(s []*launderpkg.Immutable)
source

type Tamper

struct
1type Tamper struct {
2	Field string
3}
source

Tamper has the SAME underlying struct layout as launderpkg.Immutable. /p/launderpkg deliberately gave Immutable no mutator method — callers were supposed to be unable to write its Field. /p/attack declares its own type with the same layout and adds a mutator. An attacker that holds a *launderpkg.Immutable can convert it to *Tamper and invoke Tamper.Set — the conversion is purely a type-tag change, the pointer still aliases victim's persisted memory. PushFrameCall for Tamper.Set then sees recv stamped with victim's realm (the underlying object is unchanged) and borrow-routes m.Realm to victim. The write succeeds.

Methods on Tamper

func Set

method on Tamper
1func (t *Tamper) Set(s string)
source

Set is the mutator that launderpkg.Immutable deliberately did NOT expose. /p/attack adds it via the parallel-type trick.

type Tamperer

struct
1type Tamperer struct{}
source

Tamperer is a stamped /p/attack value (constructed at init under /p/attack's realm context, stamped /p/attack, persisted Frozen). Methods on Tamperer get receiver-borrowed to /p/attack at call time — useful as a control to compare against attacks where the receiver is victim-stamped.

Methods on Tamperer

func TamperMethod

method on Tamperer
1func (Tamperer) TamperMethod(o *launderpkg.Object, s string)
source

TamperMethod is a /p/attack-defined method. When the caller invokes Tamperer{}.TamperMethod(o, s), the receiver Tamperer{} is constructed in the caller's realm, so receiver-borrow lands at the caller's realm, not /p/attack — the receiver carries the caller's stamp, not /p/attack's.

Imports 1

Source Files 2