On August 19, 2026, Canonical announced it would fund a three-year PhD project with the University of Bristol to research automated translation from C to Rust. UK Research and Innovation (UKRI) will also provide funding, with the goal of building a foundation for converting C repositories spanning hundreds of thousands of lines into Rust code that is safe, behaviorally equivalent, and maintainable. The research is expected to begin in late 2026.

However, no product decision has been made to replace AppArmor or snap-confine with Rust. What Canonical is attempting is a harder problem than simply having an LLM write code: breaking large C codebases into meaningful units, treating generated output with suspicion, and running verification and repair loops until there is evidence that original behavior has been preserved. Whether this succeeds will determine the value of the research.

AD

Compiling Isn't the Same as Finishing the Migration

Existing translators can process large volumes of C code, but they tend to carry over C's structure directly into Rust. C2Rust, a well-known example, describes its output as faithfully mirroring the input C in "non-idiomatic Rust" that includes unsafe blocks, explicitly noting that additional work is needed to produce safe, idiomatic Rust. It's an intermediate artifact that prioritizes preserving functionality—not a finished product ready to be maintained as-is.

LLMs have the opposite strength. For narrowly scoped functions, they can restructure code into idiomatic Rust using ownership and borrowing. But across a repository spanning hundreds of thousands of lines, it's impossible to survey all types, dependencies, and behaviors at once. Code that looks natural and compiles cleanly offers no guarantee that it performs the same job as the original program.

This distinction matters for what "safety" actually means. Staying within the bounds of safe Rust lets the compiler prevent many kinds of invalid memory access. But errors in permission logic, misread specifications, and behavioral drift from the original code can still slip through. The point of migrating C to Rust isn't to eliminate the word unsafe—it's to move to a maintainable design without losing the knowledge embedded in the existing code.

Canonical has already adopted Rust-based uutils coreutils and sudo-rs in Ubuntu. But both were mature, hand-crafted reimplementations. This new automated-translation research will test whether far less certain, machine-generated output can be raised to that same standard of adoption.

Four Stages That Determine Whether the Translation Succeeds

Professor Meng Wang of the University of Bristol will lead the research, co-supervised by Dr. Cristina David of the same university and Jon Seager, Canonical's VP of Engineering. Alex Wood has been selected as the PhD student. The project will use a neuro-symbolic approach, combining machine learning with program analysis, testing, and formal methods.

Stage Role What Happens If It Fails
Scheduling Splits the repository into units that preserve types and dependencies, and determines translation order Assumptions located elsewhere get overlooked, producing mistranslations that look correct for individual functions
Translation An LLM, trained or fine-tuned on existing C-to-Rust translation examples, expresses intent using Rust abstractions Code either just mirrors C's structure or becomes a plausible but different implementation
Verification Compares behavior between the C and Rust versions, attempting fuzzing and equivalence checking Correctness can only be confirmed for the inputs that were actually tested
Debugging and Repair Narrows down the cause of verification failures and fixes the relevant sections through symbolic program repair Becomes an iterative process of rewriting everything, where fixes break other behaviors

Of these four stages, the LLM only handles part of the translation. Poor splitting leaves out necessary context; weak testing lets mistranslations through. If the repair loop can't be localized, the larger the scale of conversion, the harder it becomes to track the impact of changes. This is why Canonical insists it won't trust generated code "until there's evidence it preserves the intended behavior."

Difficult challenges also exist on the verification side. C has undefined behavior and implementation-dependent behavior, and in some cases it's not even clear what should count as "the same." With pointer-heavy APIs or concurrent processing, it becomes difficult to map results converted into Rust-style data structures back onto the original implementation. Once you factor in boundaries with external libraries and OS-specific processing, matching unit tests alone isn't enough.

AD

Why AppArmor and snap-confine

AppArmor and snap-confine are not small research subjects. AppArmor is a Linux Security Module implementation used in Ubuntu that restricts process permissions based on profiles. snap-confine is the internal tool that builds the execution environment for Snap applications, enabling AppArmor profiles, seccomp filters, and mount namespaces.

Both deal with deciding "what to permit and what to deny" at the boundary between the OS and applications. Years of modifications have accumulated build-system complexity and platform-specific behaviors. Even error paths that are rarely triggered embed knowledge gained from past bugs. Translating function by function and passing existing tests risks dropping assumptions shared across distant modules or exceptions that only apply at runtime.

That's exactly why these case studies have value. However, Canonical has explicitly stated this is not a commitment to replace either piece of software with generated Rust. The scope, the version to be evaluated, and the criteria for any adoption decision have not been announced. Even if the research succeeds, the results may end up limited to splitting methods, verification techniques, and translation datasets.

From 15 Out of 100 to Further Progress—And the Verification Wall That Remains

CRUST-Bench, published in 2025, paired 100 C repositories with hand-designed safe Rust interfaces and tests. At the time of the paper's evaluation, even the best-performing model, OpenAI's o1, solved only 15 out of 100 in a single generation attempt. The difficulty of handling dependencies across an entire repository while simultaneously passing compilation and tests shows up clearly in that number.

Subsequent preprints report progress. Reboot, published in June 2026, converted six interpreters written in 6,000 to 23,000 lines of C into safe Rust, reporting that each project required between one and eleven brief human interventions. Instead of cutting the code by function, Reboot built a fully working intermediate version with features removed one at a time, then progressed through translation and verification while restoring features from the simplified version. It's an example that answers Canonical's challenge of how to split large-scale code, from a different angle.

However, in Reboot, while all tests provided during development passed completely, the pass rate dropped to 62–92% on verification tests that were withheld from the model. Satisfying known tests is not the same as preserving original behavior on unseen inputs. This is a preprint-stage result from the authors themselves, and it cannot be directly applied to AppArmor or snap-confine.

Even if Canonical's research can process hundreds of thousands of lines, the number of lines translated alone cannot be called success. What needs to be confirmed is which behavior was used as the baseline, how well the results matched under withheld tests and across multiple environments, and how unsafe code and external boundaries were managed. It would also help to publish whether performance was preserved, how much human effort was required, and whether the resulting code turned out to be something existing maintainers could actually take over. Only once this evidence is assembled will automated translation move closer to Ubuntu's security boundary.