Skip to content

v1.16

Latest

Choose a tag to compare

@github-actions github-actions released this 15 Oct 20:18
· 2 commits to master since this release

Based on upstream DFRoot 4.5 (upstream 4.2 - 4.5 merged into this fork).

Engine - vendor hardening is patched in place instead of removed (issue #21)

  • The kernel module no longer runs rmmod oplus_secure_harden, oplus_security_keventupload and
    oplus_security_guard. Removing them on an Oppo/OnePlus kernel tripped the vendor security anti-tamper path
    and black-screened the device on every run - reported on a OnePlus Ace6 (ColorOS 16.0.7.101).
  • patch_fn_ret_zero() writes mov w0, #0; ret over the offending handlers instead, so the modules stay loaded
    and their checks simply return allowed: the two oplus_* handlers, and Samsung's task_defex_enforce and
    task_defex_user_exec, which in 1.15 were kprobes rewriting x0 on every hit. It skips a
    BTI/PACIASP/PACIBSP preamble and emits retaa/retab only where the SoC has pointer authentication.
  • call_usermodehelper_exec is called with UMH_WAIT_EXEC instead of UMH_WAIT_PROC, so the module no longer
    waits for the helper to exit. That wait is the other half of the MTK reboot, and the status it reported is
    the returned 256 a Samsung saw in 1.15 (issue #5) - which also retires the exit 0 workaround, since there
    is no longer a failing command at the end of the chain to mask.
  • Housekeeping: the module fails its own init with -ENODEV to get itself unloaded, and bootstrap runs
    rmmod dfroot once late-load has finished and before a soft-reboot, rather than only at the very end where a
    reboot skipped it.
  • The .ko keep their .note.gnu.build-id, which upstream had stopped stripping - that is what kept a Galaxy
    A34 (SM-A346M, kernel 6.6.92) from loading the module at all.

Engine - the payload gets a place to live on more devices

  • The shellcode no longer has to fit in the slack after the end of the executable PT_LOAD segment. The loader
    scans that segment for a run of zero bytes - the alignment padding between functions - big enough to hold it,
    prints the offset it chose, and reports the largest run it found when there is none, so a log says something
    useful instead of a bare [-] Failed to find a suitable code cave.
  • Hook-site preambles are recognised properly now: PACIASP, PACIBSP, BTI, BTI c, BTI j and BTI jc,
    up to two words deep, where before only PACIASP and one form of BTI were handled once.

App

odin
  • An Odin pill sits left of the menu button, in the same 44dp capsule as that button, and its dot says
    whether this firmware will let the device into Odin - Galaxy firmwares from around April 2026 answer download
    mode with a D2 error while a lock-screen credential is set. Green means not gated, red means it is, grey means
    this device does not gate download mode at all. Tapping it opens the three facts behind the dot - Lockscreen,
    Maintenance Mode, Device - so a dot you disagree with is arguable without a cable. It reads the two public
    inputs DmcService builds its decision from, not the TEE vault behind them, because DirtyFrag is the tool
    that gets you root and so has to work on a device that has none.
update
  • The version number is out of the header and the update has taken its place: when a newer release is
    published, a lime capsule wipes in over the word DirtyFrag and reads Update, one tap from the release
    page. The digits it replaces were 10.8sp next to a 24sp word, and reserved their width whether or not an
    update was flagged, which with the wider Odin pill beside them left the title ellipsized. The version is only
    relocated: version <x> to logcat on every start, app version: <x> in the run log.
ui
  • The interface keeps its own scale. Every measurement in it belongs to one screen width in dp, so a single One
    UI screen-zoom step clips the title and the default font size breaks it outright; ScaleFix now derives a
    density from the real pixel width so the app always lays out at 384dp - a Galaxy S25 at 450dpi - and pins
    fontScale to 1.0. Verified on an SM-S931B at every screen zoom and font size step. The price is that Screen
    zoom and Font size no longer apply inside the app, and wide screens - a foldable opened flat, a tablet - are
    the known gap, because the correction is capped at 30%.
  • No more toasts. Flipping the KSU modules switch, resetting the layout, tapping a manager that cannot be
    launched: the switch already says what it did in its own subtitle, the reset is visible in the stack, and
    neither launcher can strand anyone when there is nothing to launch.
  • run() is synchronized and returns early when /dev/df already exists, so the boot autorun racing a
    manual tap no longer re-hooks over the first run and corrupts it.

Managers

  • zandatsu07's KernelSU-Next is no longer listed as a Samsung manager, following upstream: it only worked on
    S23 and below with kernel 5.15. diabl0w's KernelSU stays the Samsung manager, and the non-Samsung list is
    unchanged.

Fixed - unsafe getprop fallback

Upstream's fallback for kernels that leave the Android version out of uname -r never checked the popen()
result and rebuilt the version string with sprintf into a 15 byte stack buffer from a 5 byte read, so a long
or non-numeric property overflowed it. The property is now read into a zero-initialised buffer and only a
leading integer is accepted. The same hardening shipped in
k10halifa/Dslice.

Built

  • The eight embedded kernel modules are rebuilt by CI from this source, so the APK carries exactly this engine.
  • The bundled Inter variable font is subset down to the glyphs the app can render: 332,804 bytes out of the
    APK
    - 2.26 MB down to 1.93 MB, about a seventh of the download. It is the same font: Inter carries no
    hinting tables at all, so a subset cannot change how a surviving glyph rasterises, and that was checked
    rather than assumed - both fonts instantiated at the two weights the app declares, every contour coordinate
    and advance width compared over all 86 characters the app can put on screen, at zero differences. Anything
    outside the subset falls back per character, the way emoji already did.
  • android:debuggable="true" is gone from the manifest, where upstream has carried it since its first commit.
    A debuggable APK can be run-as and ptraced by anything that has adb - readable preferences and an
    injectable process sitting next to an exploit. Nothing in the app needs it, so no behaviour changes.