Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Intelligence View
⚡ tsecurity.de Intelligence

The Rust binding compiled fine. then it started segfaulting in prod

I run a free image converter, its built on rust + axum + libvips. it had been happily running for months. then one feature, images-to-pdf, started falling over in production with this: g_object_unref: assertion 'G_IS_OBJECT (object)'…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

I run a free image converter, its built on rust + axum + libvips. it had been happily running for months. then one feature, images-to-pdf, started falling over in production with this:




g_object_unref: assertion 'G_IS_OBJECT (object)' failed






and the fun part: only sometimes. convert a couple images, fine. convert a few more, boom. the non-deterministic kind of crash, which is the worst kind, because it makes you sit there wondering if you even understand the language you've been writing for years.



Turns out the bug was mine. the trigger was one tiny innocent .clone(). heres the whole thing because i'm pretty sure other people doing rust over a C lib will eventually step on the same rake.






"But rust is memory safe"



This is what messed with my head for a while. rust is supposed to stop exactly this. no double frees, no use after free, borrow checker has your back. so how am i double freeing anything at all?



One word makes all those guarantees quietly disappear: FFI.



Libvips is a C library built on GObject, and GObject does its own manual reference counting. the rust crate wraps those C objects in rust types. and the second a rust type is holding a raw pointer into C land, the borrow checker just... cant help you anymore. it sees a struct. it does not see that the struct is actually a handle to a refcounted thing living on the C heap. safety stops right at that line and nobody tells you.






The actual cause: a Clone that doesnt clone



Heres roughly what was blowing up. i was building a multi-page pdf and somewhere in the loop i cloned the image:




// the crash version
let copy = image.clone();
// ... use copy ...
// both `image` and `copy` drop here






VipsImage in the crate derives Clone. and a derived clone on a thing that holds a pointer does the obvious dumb thing: it copies the pointer. bit for bit. so now the same C object has two rust owners, and here is the kicker, nobody incremented the GObject refcount. libvips still thinks there is exactly one reference to that object.



Then rust does its job a little too well. both values go out of scope, Drop runs twice, and each drop calls g_object_unref on the same object. first unref takes the count to zero and frees it. second unref runs on already-freed memory, libvips checks G_IS_OBJECT, the assertion blows, and depending on timing you either get a glib critical or a clean segfault.



So. a textbook double free. wearing a .clone() as a disguise. the "random" part was just the allocator deciding whether the freed slot had been reused yet or not.



A correct clone here would have to call g_object_ref so each owner actually accounts for its own reference. the derived one doesnt. so calling it Clone is generous. its an aliased pointer with two destructors aimed at it.






The fix



Stopped cloning the handle, started asking libvips for a real new object instead:




// the fixed version
let copy = ops::copy(&image)?;






ops::copy runs an actual libvips copy and gives you back a fresh GObject with its own refcount. now each rust value owns its own distinct C object, each drop unrefs its own thing, nothing gets freed twice. crash gone.



one line. took me a couple evenings to be sure it was that line, which is always how these go.






a few more libvips + rust landmines from the same evening



since i was already in there bleeding, a few neighbours showed up:



JpegsaveBufferOptions::default() hands you a busted keep value. the default came out as something like keep | 32, which libvips just rejects with a glib critical. fix was to stop trusting the default and set it myself:




keep: ops::ForeignKeep::None,






the operation cache was a second way to die. libvips caches operations by default, and under load that cache plus the lifecycle mess above gave me another crash, this time inside cache trimming. i turned the operation cache off entirely while getting things stable, which killed that path. just know it exists and that its global state.



VipsApp::new(name, false) is not what it looks like. that second bool is detect_leak, not some concurrency switch, which is exactly what i had lazily assumed it was. read the signature, dont pattern-match on vibes.



bumping the crate did not save me. i tried going from 1.7.x up to 2.1.0 hoping the lifecycle stuff was just fixed upstream. nope, changed nothing for this. reverted to 1.7.6 and fixed it properly on my end.






what i actually took from this



a derived Clone on a type that wraps a foreign, refcounted resource is a trap. #[derive(Clone)] assumes a clone is a cheap copy-the-fields job. for a GObject handle thats the exact wrong assumption: copy the pointer without taking a ref and you've got two owners, one refcount, and rust's own Drop happily freeing it twice.



so the rule i walked out with: when a rust type owns a C resource that has its own lifecycle, treat Clone and Drop as suspects, not freebies. need another handle? reach for the library's own copy/ref function before you derive Clone and hope.



if you've hit something like this with libvips bindings or any GObject FFI, i'd genuinely love to hear how you dealt with it, the comments are the fun part. the tool this was all holding up is at convertifyapp.net if you want a look. no account, files get deleted after.

1. Sofort-Triage & Abwehrmaßnahmen

SOC Incident Playbook: Remote Code Execution (RCE) Defense
Syntax validiert (0 Fehler)
title: Detect Exploitation - The Rust binding compiled fine. then it started segfaulting in prod
id: ccbd80e3-da89-4301-9840-2f3d0b2969ef
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-26
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
Syntax validiert (0 Fehler)
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-26"
        description = "YARA Signature for "
    strings:
        $str = "The Rust binding compiled fine" ascii wide
    condition:
        any of them
}
Syntax validiert (0 Fehler)
index=security sourcetype IN ("cisco:asa", "pan:traffic", "zeek_conn", "suricata", "WinEventLog:Security")
("The Rust binding compiled fine then it s")
| stats count earliest(_time) as first_seen latest(_time) as last_seen by src_ip, dest_ip, dest_host, signature
| eval first_seen=strftime(first_seen, "%Y-%m-%d %H:%M:%S"), last_seen=strftime(last_seen, "%Y-%m-%d %H:%M:%S")
| sort - count
Syntax validiert (0 Fehler)
message: "*The Rust binding compiled fine then it s*"
Syntax validiert (0 Fehler)
CommonSecurityLog
| where Message has "The Rust binding compiled fine then it s"
| summarize EventCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationIP, DestinationPort, Activity
| extend DetectionRule = "iShareStuff-CTI-Compiled"
| sort by EventCount desc

2. Cyber Threat Intelligence & Forensik

CTI Threat Relationship Graph2 Knoten / 1 Relationen
CVE / Incident Software MITRE ATT&CK CWE Weakness IoC
🎯
MITRE ATT&CK Matrix Navigator 14 Taktiken
Reconnaissance
-
Resource Development
-
Initial Access
Execution
Persistence
-
Privilege Escalation
Defense Evasion
Credential Access
-
Discovery
-
Lateral Movement
-
Collection
-
Command and Control
Exfiltration
-
Impact
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Kognitive Analyse für identifizierte Bedrohung: Erhöhte Bedrohungslage im Bereich The Rust binding compiled fine. then it .... Basierend auf 368k Vektor-Korrelationen werden sofortige Isolationsmaßnahmen für betroffene Endpunkte empfohlen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

⚡ Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
🔗 Semantisch verwandte Zero-Days MariaDB 11.7 VEC
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten The Rust binding compiled fine. then it started segfaulting in prod

Thematisch verwandte Begriffe: Rust, binding, compiled, fine · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-100503 | Ghidra versions through 12.1.4 contain a heap use-after-free vulnerabil…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag