Skip to content

android: redirect init rc paths without overwriting buffers - #313

Open
xeropresence wants to merge 1 commit into
bmax121:mainfrom
xeropresence:fix/init-rc-redirection
Open

xeropresence wants to merge 1 commit into
bmax121:mainfrom
xeropresence:fix/init-rc-redirection

Conversation

@xeropresence

Copy link
Copy Markdown

Summary

Redirect init's openat filename through temporary userspace stack storage instead of overwriting the caller's filename allocation. Restore the syscall argument afterward without copying into the original buffer.

Problem

The existing path tries to copy /dev/user_init.rc over init's supplied filename. That replacement does not necessarily fit: /init.rc is shorter. The after-hook then restores an entire 64-byte ORIGIN_RC_FILES table entry, even though that table-entry size says nothing about the capacity of init's allocation.

Those writes can corrupt userspace memory or fault on hardened configurations. The fallback also writes directly to args->arg1, which is not the filename argument when a syscall wrapper supplies pt_regs.

Changes

  • Copy the replacement path to 16-byte-aligned userspace stack storage and redirect only after the complete NUL-terminated path has been copied.
  • Save, replace, and restore the filename with syscall_argn / set_syscall_argn so wrapper-based syscall hooks are handled correctly.
  • Reject a truncated filename read before comparing it as a C string.
  • Close the replacement file if reading the original rc file fails.
  • Remove the redundant apd uid-listener & rc command. Init passes & as a literal argument rather than shell backgrounding syntax, and APatch's boot-completed handler already starts the listener.

The original filename buffer is never modified. A failed replacement-path copy leaves the original syscall argument in place, and the one-shot hook cleanup remains enabled. No GrapheneOS-specific feature disable or persistent preset-format change is introduced.

Verification

Built the Android ARM64 payload and kptools on this branch.

Device testing used all three fixes on KernelPatch 0.13.8, with a Pixel 8 running GrapheneOS 2026081300:

  • Init opened the replacement for /system/etc/init/hw/init.rc; the one-shot hook was removed.
  • APatch post-fs-data, services, and boot-completed exited with status 0.
  • One apd uid-listener process remained running.

"on property:sys.boot_completed=1\n"
" exec -- " SUPERCMD " su -Z " MAGISK_SCTX " exec " APD_PATH " -s %s boot-completed\n"
" exec -- " SUPERCMD " su event boot-completed\n"
" exec -- " SUPERCMD " su -Z " MAGISK_SCTX " exec " APD_PATH " uid-listener &\n"

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APD already starts the UID listener from on_boot_completed() via
run_uid_monitor(). The rc block already invokes boot-completed, so
this separate startup command is redundant.

The trailing & is passed to APD as a literal argument here, not
interpreted by a shell. During the earlier GrapheneOS testing, replacing
this with exec_background produced two listeners. Removing the line
left one listener running—the one started by APD's boot-completed handler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant