<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.3.4">Jekyll</generator><link href="https://muhammad-hassnain.github.io/feed.xml" rel="self" type="application/atom+xml"/><link href="https://muhammad-hassnain.github.io/" rel="alternate" type="text/html" hreflang="en"/><updated>2026-10-05T23:41:49+00:00</updated><id>https://muhammad-hassnain.github.io/feed.xml</id><title type="html">blank</title><subtitle>Muhammad Hassnain — PhD student in Computer Science at UC Davis researching Rust security, program analysis, soundness of safe abstractions, and software supply chain trust. Publications, projects (Cargo Sherlock, CratesReport, CratesDiff), paper summaries, and teaching. </subtitle><entry><title type="html">How can ‘safe’ Rust still be unsafe? A tool that hunts the gap</title><link href="https://muhammad-hassnain.github.io/blog/2026/unsafechecker-finding-soundness-bugs-rust-safe-abstractions/" rel="alternate" type="text/html" title="How can ‘safe’ Rust still be unsafe? A tool that hunts the gap"/><published>2026-09-30T00:00:00+00:00</published><updated>2026-09-30T00:00:00+00:00</updated><id>https://muhammad-hassnain.github.io/blog/2026/unsafechecker-finding-soundness-bugs-rust-safe-abstractions</id><content type="html" xml:base="https://muhammad-hassnain.github.io/blog/2026/unsafechecker-finding-soundness-bugs-rust-safe-abstractions/"><![CDATA[<p><em>A plain-language look at the paper <a href="https://arxiv.org/abs/2609.09641">“UnsafeChecker: Finding Soundness Bugs in Rust Safe Abstractions”</a> (Yin, Zhang, Feng &amp; Xu, 2026). This is the short version — the <a href="/summaries/unsafechecker-finding-soundness-bugs-rust-safe-abstractions/">full breakdown, with the methodology and every result, lives here</a>.</em></p> <p>Rust makes a strong promise: a program that compiles without ever writing the word <code>unsafe</code> will not corrupt memory. However, that promise leans on the libraries underneath it, and those libraries are full of <code>unsafe</code> code. When one of them gets a single detail wrong, an ordinary program that never wrote a line of <code>unsafe</code> can still read freed memory, run off the end of a buffer, or be exploited. A recent paper from Nanjing University builds a tool, <strong>UnsafeChecker</strong>, to hunt for exactly these hidden mistakes — and reports <strong>114 previously unknown ones</strong> in real, widely used crates.</p> <p><strong>In one sentence.</strong> UnsafeChecker reconstructs the three things Rust’s raw pointers throw away — who <em>owns</em> a value, whether it is still <em>alive</em>, and its physical <em>layout</em> (where it sits and how big it is) — and uses them to flag <code>unsafe</code> library code that would let ordinary safe code trigger undefined behavior.</p> <h2 id="how-safe-code-can-still-break">How safe code can still break</h2> <p>Library authors hide their dangerous, low-level code behind ordinary, safe-to-call APIs — a <strong>safe abstraction</strong> such as <code>Vec</code> or <code>Mutex</code>. The arrangement is a <em>contract</em>: inside the wrapper, the <code>unsafe</code> code must uphold by hand the invariants the compiler would otherwise enforce. Break that contract and the abstraction is <em>unsound</em> — safe callers who never wrote a line of <code>unsafe</code> can still hit undefined behavior: out-of-bounds reads, use-after-free, double frees, and the exploits that follow.</p> <p>An analogy that maps onto the mechanism. Picture an automated warehouse where every item has three facts on file: who holds its single claim ticket (ownership), its status stamp — stocked, shipped, incinerated (lifecycle), and its physical footprint on the shelves (layout). A <strong>raw pointer is a bare shelf coordinate on a sticky note</strong>, with none of those three facts attached. UnsafeChecker is the auditor who walks the floor and rebuilds the manifest from those coordinates, then flags any operation that would reach past an item, touch one already incinerated, or photocopy a claim ticket so two parts of the program each try to dispose of the same item.</p> <figure style="text-align:center; margin: 1.8rem 0;"> <svg viewBox="0 0 640 430" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="A mistake inside a safe abstraction's unsafe interior lets 100% safe caller code reach undefined behavior" style="max-width:100%;height:auto;font-family:inherit;color:var(--global-text-color);"> <defs> <marker id="ab-arrow" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L7,3 L0,6 Z" fill="currentColor"/></marker> <marker id="ab-danger" markerWidth="9" markerHeight="9" refX="7" refY="3" orient="auto" markerUnits="strokeWidth"><path d="M0,0 L7,3 L0,6 Z" fill="#e0483f"/></marker> </defs> <rect x="40" y="18" width="360" height="92" rx="10" fill="currentColor" fill-opacity="0.045" stroke="currentColor" stroke-dasharray="6 5"/> <text x="58" y="43" font-size="13" fill="currentColor" opacity="0.65">Your program — no <tspan font-family="monospace">unsafe</tspan> anywhere</text> <text x="58" y="70" font-size="14.5" fill="currentColor" font-weight="600" font-family="monospace">let b = Buffer::new();</text> <text x="58" y="93" font-size="14.5" fill="currentColor" font-weight="600" font-family="monospace">let x = b.get(999);</text> <line x1="220" y1="110" x2="220" y2="142" stroke="currentColor" stroke-width="2" marker-end="url(#ab-arrow)"/> <rect x="80" y="142" width="280" height="50" rx="10" fill="var(--global-theme-color)" fill-opacity="0.13" stroke="var(--global-theme-color)" stroke-width="2"/> <text x="220" y="172" font-size="14" fill="currentColor" text-anchor="middle" font-weight="600">Safe API surface — the <tspan font-family="monospace">get()</tspan> method</text> <text x="372" y="167" font-size="12" fill="var(--global-theme-color)" font-weight="700">UnsafeChecker</text> <text x="372" y="183" font-size="12" fill="var(--global-theme-color)" font-weight="700">audits here ◀</text> <line x1="220" y1="192" x2="220" y2="224" stroke="currentColor" stroke-width="2" marker-end="url(#ab-arrow)"/> <rect x="40" y="224" width="360" height="150" rx="10" fill="currentColor" fill-opacity="0.06" stroke="currentColor"/> <text x="58" y="247" font-size="13" fill="currentColor" opacity="0.65">inside the library (hidden from you)</text> <rect x="58" y="258" width="150" height="98" rx="8" fill="currentColor" fill-opacity="0.03" stroke="currentColor"/> <text x="133" y="286" font-size="13" fill="currentColor" text-anchor="middle" font-weight="600" font-family="monospace">unsafe {</text> <text x="133" y="306" font-size="12.5" fill="currentColor" text-anchor="middle" font-family="monospace">ptr.add(i)</text> <text x="133" y="330" font-size="11.5" fill="currentColor" text-anchor="middle" opacity="0.7">raw pointer =</text> <text x="133" y="346" font-size="11.5" fill="currentColor" text-anchor="middle" opacity="0.7">a bare address</text> <rect x="222" y="258" width="160" height="98" rx="8" fill="currentColor" fill-opacity="0.03" stroke="currentColor"/> <text x="302" y="283" font-size="12.5" fill="currentColor" text-anchor="middle" font-weight="600">Contract, upheld</text> <text x="302" y="300" font-size="12.5" fill="currentColor" text-anchor="middle" font-weight="600">by hand:</text> <text x="302" y="323" font-size="12.5" fill="currentColor" text-anchor="middle">ownership ·</text> <text x="302" y="340" font-size="12.5" fill="currentColor" text-anchor="middle">validity · layout</text> <path d="M400,300 C500,300 500,64 406,64" fill="none" stroke="#e0483f" stroke-width="2.5" marker-end="url(#ab-danger)"/> <text x="512" y="150" font-size="13" fill="#e0483f" font-weight="700"> <tspan x="512" dy="0">break the</tspan> <tspan x="512" dy="17">contract →</tspan> <tspan x="512" dy="17">undefined</tspan> <tspan x="512" dy="17">behavior in</tspan> <tspan x="512" dy="17">your safe code</tspan> </text> </svg> <figcaption style="font-size:0.85rem; color: var(--global-text-color-light);">A safe abstraction hides <code>unsafe</code> behind a normal API. If the interior breaks its contract, safe callers can still trigger undefined behavior — the boundary UnsafeChecker guards.</figcaption> </figure> <h2 id="why-it-matters">Why it matters</h2> <p>The whole Rust ecosystem is built on trusting that these <code>unsafe</code>-inside wrappers keep their promises. UnsafeChecker is a compiler plugin that rebuilds ownership, lifecycle, and layout from raw pointers, carries all three in one shared state as it walks the code, and checks two things: dangerous operations <em>as they happen</em>, and — this is the part a pattern-matcher cannot do — whatever leaks back out through the safe API <em>at each function’s exit</em>. On a benchmark of 46 real CVEs it caught <strong>32 (69.6%)</strong>, against 11 for the best prior tool, finding more than 20 that every baseline missed. Then it scaled to 100,000+ crates in two days and surfaced 114 real, previously unknown bugs; maintainers have already fixed 27, and 11 have public vulnerability identifiers.</p> <figure style="text-align:center; margin: 1.5rem 0;"> <img src="/assets/img/rust-digest/unsafechecker-finding-soundness-bugs-rust-safe-abstractions/benchmark_detection.png" alt="Grouped bar chart: CVEs detected and bugs covered on the RustSec benchmark. MirChecker 0, SafeDrop 1, Rudra 11, UnsafeChecker 32 CVEs / 36 bugs." style="max-width:100%;height:auto;border-radius:10px;border:1px solid rgba(128,128,128,0.18);box-shadow:0 1px 4px rgba(0,0,0,0.07);"/> </figure> <p>It is not magic. About half its alerts are false alarms (51.6% precision), it misses roughly a third of the benchmark bugs, and it does not touch concurrency. It is a fast, sharp bug-_finder_ for the authors of <code>unsafe</code>-heavy libraries — not a proof of soundness.</p> <h2 id="the-one-thing-to-remember">The one thing to remember</h2> <p>“Safe Rust” is a promise your libraries make on your behalf. Most keep it. Tools like UnsafeChecker are how we find the ones that quietly do not — before an attacker does.</p> <hr/> <p>Want the details — the full three-domain methodology, the complete results, a compile-checked code example, and the open questions? <strong><a href="/summaries/unsafechecker-finding-soundness-bugs-rust-safe-abstractions/">Read the full summary</a>.</strong></p> <p style="font-size:0.8rem; color: var(--global-text-color-light);"> Produced by a multi-agent pipeline I built with <a href="https://claude.com/claude-code">Claude</a> — drafted, independently fact-checked, edited for writing, and rewritten in my own voice — then reviewed by me before posting. The plots are my own, from the paper's reported numbers. </p>]]></content><author><name></name></author><category term="rust"/><category term="rust"/><category term="research-summary"/><category term="security"/><summary type="html"><![CDATA[UnsafeChecker reconstructs the ownership, lifecycle, and layout facts raw pointers erase, and uses them to find unsafe library code that lets ordinary safe Rust hit undefined behavior — 114 real bugs, and counting.]]></summary></entry><entry><title type="html">Work in Progress</title><link href="https://muhammad-hassnain.github.io/blog/2024/coming-soon/" rel="alternate" type="text/html" title="Work in Progress"/><published>2024-12-20T00:00:00+00:00</published><updated>2024-12-20T00:00:00+00:00</updated><id>https://muhammad-hassnain.github.io/blog/2024/coming-soon</id><content type="html" xml:base="https://muhammad-hassnain.github.io/blog/2024/coming-soon/"><![CDATA[]]></content><author><name></name></author><summary type="html"><![CDATA[I plan to have different categories, i.e, cooking recipies, rust, and security/privacy, blog/pictures etc.]]></summary></entry></feed>