Adding a Syscall to Android 12 Kernel from Source Code

Adding a Syscall to Android 12 Kernel from Source Code

This article is an excellent piece from the Kanxue Forum.

Kanxue Forum Author ID: xxxlion

Adding a syscall to Android 12 involves quite a bit, and the information available online is often outdated (especially regarding bionic). I encountered many pitfalls along the way. I decided to write this article to document how to add a syscall to Android 12. (There are still issues; I can’t see the printk logs in dmesg.)
Environment: lineageos 19.1
Compilation Environment: Ubuntu 20.04
In fact, the order I performed the operations is the reverse of what is presented here; writing in chronological order is more convenient for viewing.

1. Add an Exported Symbol to libc (Optional)

By directly adding a call in the Linux kernel, you can implement a custom syscall using syscall(_NR_ID). I noted this down as I learned about it.

bionic calls gensyscall.py, reads from SYSCALL.TXT, and determines which functions need to generate syscall assembly instructions.Adding a Syscall to Android 12 Kernel from Source CodeAdding a Syscall to Android 12 Kernel from Source CodeIn unistd.h, add the syscall ID, just follow the format of others; sys_antidebug_update is a custom function in the Linux kernel, which will be mentioned below.Adding a Syscall to Android 12 Kernel from Source CodeFor example, I added the __antidebug_update function here, which will call the antidebug_update function in the Linux kernel, specifically for the arm64 architecture.
The meaning of this line: return_type func_name[|alias_list]:syscall_name[:socketcall_id] arch_list
# <sys/resource.h>int __antidebug_update:antidebug_update(pid_t) arm64int getrusage(int, struct rusage*) allint __getpriority:getpriority(int, id_t) all
The generated results are as follows:
Adding a Syscall to Android 12 Kernel from Source CodeAdding a Syscall to Android 12 Kernel from Source Code
Once the assembly for this function is generated, you can directly call the __antidebug_update function in your code using extern “C” (which is essentially a syscall). I didn’t want to modify the makefile, so I used an existing kernel cpp instead.Adding a Syscall to Android 12 Kernel from Source CodeThen, add the exported symbol to libc, compile it in this path, and you can directly call the libc function to implement the encapsulated syscall.Adding a Syscall to Android 12 Kernel from Source CodeYou can see the map file generated by the bionic tool here:Adding a Syscall to Android 12 Kernel from Source Code

Pitfall 1

The syscall number _NR_xxx in bionic is copied from external/kernel-headers/original/uapi/asm-generic/unistd.h, so you need to modify this file; simply changing the include won’t work. Here, I added a macro to limit the generation of syscalls for arm64, and the same limitation needs to be applied in the Linux kernel.Adding a Syscall to Android 12 Kernel from Source Code

Pitfall 2

If you don’t want to export your own function for arm’s libc and only want to export it for arm64, you must add the precompiled macro in the function declaration. I have already added a macro in unistd.h that limits the generation of antidebug_update only for arm64 architecture; if you don’t add this, bionic will attempt to use the arm architecture’s antidebug_update syscall assembly, which will cause an error because it can’t find it.
Adding a Syscall to Android 12 Kernel from Source CodeLater at the user level, you can declare aadebug using extern “C”, and then call it directly.

2. Add Syscall in the Linux Kernel

First, look at exception dispatching. kernel\xiaomi\sm8250\arch\arm64\kernel\entry.S calls syscall, which generates an interrupt. In arm64 assembly, this is svc, and after the interrupt generates an exception, it enters the svc handler.Adding a Syscall to Android 12 Kernel from Source CodeIn kernel\xiaomi\sm8250\arch\arm64\kernel\syscall.c, I copied a key piece of code.
asmlinkage void el0_svc_handler(struct pt_regs *regs){    sve_user_discard();    el0_svc_common(regs, regs->regs[8], __NR_syscalls, sys_call_table);} static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,               const syscall_fn_t syscall_table[]){       unsigned long flags = current_thread_info()->flags;     regs->orig_x0 = regs->regs[0];    regs->syscallno = scno;         ...    invoke_syscall(regs, scno, sc_nr, syscall_table);        ...}static long __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn){    return syscall_fn(regs);} static void invoke_syscall(struct pt_regs *regs, unsigned int scno,               unsigned int sc_nr,               const syscall_fn_t syscall_table[]){    long ret;    if (scno < sc_nr) {        syscall_fn_t syscall_fn;        syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)];        ret = __invoke_syscall(regs, syscall_fn);    } else {        ret = do_ni_syscall(regs, scno);    }     regs->regs[0] = ret;}
To summarize in one sentence:
syscall_table[scno](regs);
During compilation, the syscall_table is generated, indexing to the handler’s address based on the ID (so hooking the syscall function can directly replace the function address obtained from syscall_table[id], and the main task is to find the address of syscall_table and call back to the original function for processing).
To add a syscall, you need to do two things: define a handler (declared using the SYSCALL_DEFINEx macro, where x is the number of parameters; you can understand the specific details by looking at other function implementations) and increase NR_ID (if you did the first point, the bionic NR_ID and Linux NR_ID need to match).
(1) Define the handler
For convenience, I used the existing file kernel\xiaomi\sm8250\kernel\sys.cAdding a Syscall to Android 12 Kernel from Source Code
Add NR_ID carefully, because I also added a syscall in bionic, it needs to match here. sys_antidebug_update, the prefix sys is added by the SYSCALL_DEFINEx macro, so you need to include sys; you can see other syscall declarations or expand the macro to understand.
Adding a Syscall to Android 12 Kernel from Source Code
After adding, if the build compiles without errors, flash the device, and you can directly write a demo to verify.Adding a Syscall to Android 12 Kernel from Source CodeUse aarch64-linux-gnu-gcc to compile (you can directly install the arm cross-compilation tools via apt on Ubuntu); don’t forget the -static option. Flash it to your phone and run it; you can see that the function logic is executed.
Passing in the parameter 123, return 123+100, so the syscall works fine.Adding a Syscall to Android 12 Kernel from Source CodeHowever, I still can’t see where the printk logs are going; I plan to encapsulate a function to write the logs to a file.There are so many unistd.h files, it makes one dizzy..
Modifying the source code and recompiling takes a lot of time. Installing a driver (.ko) is more common; if needed, just hook the syscall since it has better extensibility. I have tried turning off the signature verification in the kernel compilation options, allowing the installation of unsigned drivers, but I still couldn’t get the printk logs to show. However, customizing the kernel in your own environment is still the most convenient, as the goal is to achieve “one-time effort for lasting benefits.”

Adding a Syscall to Android 12 Kernel from Source Code

Kanxue ID: xxxlion

https://bbs.kanxue.com/user-home-792494.htm

*This article is originally by Kanxue Forum xxxlion. Please indicate that it comes from the Kanxue community when reprinting.
Adding a Syscall to Android 12 Kernel from Source Code

# Previous Recommendations

1.CVE-2022-21882 Privilege Escalation Vulnerability Study Notes

2.wibu Certificate – Initial Exploration

3.Reverse Engineering of APIC Interrupts in Win10 1909

4.Analysis and Simulation of EAF Mechanism under EMET

5.SQL Injection Learning Sharing

6.Issues and POCs of V8 Array.prototype.concat Function

Adding a Syscall to Android 12 Kernel from Source Code
Adding a Syscall to Android 12 Kernel from Source Code

Share

Adding a Syscall to Android 12 Kernel from Source Code

Like

Adding a Syscall to Android 12 Kernel from Source Code

Watch

Leave a Comment