termux / proot

An chroot-like implementation using ptrace.
https://wiki.termux.com/wiki/PRoot
Other
745 stars 161 forks source link

What has the <extension> done ? #224

Closed w296488320 closed 2 years ago

w296488320 commented 2 years ago

I m trying to learn this code but I don t understand what is do in the 《extension 》directory ? The good thing is processing some callback information ? The fakeid0, f i x symlink _ s i z e... I don't know what they can do。

michalbednarski commented 2 years ago

Extensions are optional features of proot that are mostly contained within their directory (such as extension/fake_id0, though there are still hooks for them outside their directory), each of them is compiled into proot and enabled through command-line switch.

While I've got no proper documentation, you might find some information in following places:

What particular extensions do is described in command-line switches used for enabling them: https://github.com/termux/proot/blob/d4e4a07fbdc16e24868c295d3f7de97eca2a7f80/src/cli/proot.h#L193-L277

List of events on which extensions can react to is in ExtensionEvent enum: https://github.com/termux/proot/blob/d4e4a07fbdc16e24868c295d3f7de97eca2a7f80/src/extension/extension.h#L33-L150

To find when particular event is executed search for notify_extensions calls

w296488320 commented 2 years ago

I ve tried to develop demo using proot But oddly enough my seccomp filtered callback doesn t seem to be executed (case SIGTRAP | PTRACE_EVENT_SECCOMP2 and case SIGTRAP | PTRACE_EVENT_SECCOMP)

I have set up the HAVE_SECCOMP_FILTER

My code is as follows ↓ ↓ ↓ ↓ ↓ ↓ ↓


                switch (tracee->seccomp) {

                    case tracer::ENABLED:
                        LOGI("SIGTRAP | 0x80 (tracer::ENABLED)")

                        if (IS_IN_SYSENTER(tracee)) {

                            tracee->restart_how = PTRACE_SYSCALL;

                        } else {

                            tracee->restart_how = PTRACE_CONT;
                            //tracee->sysexit_pending = false;
                        }
                    case tracer::DISABLED:
                        LOGI("SIGTRAP | 0x80 (tracer::DISABLED)")

                        if (!tracee->seccomp_already_handled_enter) {

                            bool was_sysenter = IS_IN_SYSENTER(tracee);

                            translate_syscall(tracee);
....

Log log always SIGTRAP | 0x80 (tracer:: DISABLED)

I wonder why not executed (case SIGTRAP | PTRACE_EVENT_SECCOMP2 case SIGTRAP | PTRACE_EVENT_SECCOMP )

michalbednarski commented 2 years ago

Looks like you didn't call enable_syscall_filtering, so seccomp filters were not installed. Note that this filter installation has to happen in tracee process and affects only single thread. (PTRACE_ATTACH also affects only single thread)

I'm not sure what your actual goal is but chances are that something like PLTHook will be more appropriate for you than proot or ptrace

w296488320 commented 2 years ago

I think I'm already on it.I get a process A via fork () to go to (ptrace (PTRACE_ATTACH, pid, NULL, NULL);) main process). Then turn on (enable_syscall_filtering) I invited you to enter my (proot hello word) project Am I honored to invite you to help me review my code?

w296488320 commented 2 years ago
 case SIGSYS: {
                ALOGI(">>>>>case SIGSYS: ")
               siginfo_t siginfo = {};
               ptrace(PTRACE_GETSIGINFO, tracee->pid, NULL, &siginfo);
               if (siginfo.si_code == SYS_SECCOMP) {

This case was never executed causing me to return the result via seccomp mode modification.I m wondering how the proot goes down in seccomp mode where the modification returns the results.

Always print log when case SIGTRAP | PTRACE_EVENT_SECCOMP starts (skipping PTRACE_EVENT_SECCOMP for already handled sysenter)

I don't know that I didn't express clearly what I want to say, and I really hope that you can clone a copy of my proot hello word

michalbednarski commented 2 years ago

There are two seccomp polices:

  1. One is installed by proot in order to avoid using ptrace(PTRACE_SYSCALL) for every syscall, instead proot can send list of syscalls to kernel and handle them. This is handled through case SIGTRAP | PTRACE_EVENT_SECCOMP. I'd recommend omitting this filter installation until you have proot working but being too much overhead, proot will work without it.
  2. Other is installed by Android. This one is handled in case SIGSYS: and in case of normal Android application it won't be triggered

In case of your test application fopen("/proc/self/abc", "r"); is already redirected, but races against proot startup, if you wait before calling fopen it'll succeed

w296488320 commented 2 years ago
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG: *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG: Build fingerprint: 'Redmi/alioth/alioth:11/RKQ1.200826.002/V12.5.19.0.RKHCNXM:user/release-keys'
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG: Revision: '0'
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG: ABI: 'arm'
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG: Timestamp: 2022-04-30 12:47:41+0800
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG: pid: 19399, tid: 19399, name: example.jnihook  >>> com.example.jnihook <<<
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG: uid: 10407
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG: signal 6 (SIGABRT), code -1 (SI_QUEUE), fault addr --------
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG:     r0  00000000  r1  00004bc7  r2  00000006  r3  ffa171b0
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG:     r4  ffa171c4  r5  ffa171a8  r6  00004bc7  r7  0000016b
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG:     r8  ffa171b0  r9  ffa171c0  r10 ffa171e0  r11 ffa171d0
2022-04-30 12:47:41.203 19404-19404/? A/DEBUG:     ip  00004bc7  sp  ffa17180  lr  f46fa6ed  pc  f46fa700
2022-04-30 12:47:41.341 19404-19404/? A/DEBUG: backtrace:
2022-04-30 12:47:41.341 19404-19404/? A/DEBUG:       #00 pc 00062700  /apex/com.android.runtime/lib/bionic/libc.so!libc.so (offset 0x61000) (abort+172) (BuildId: edc23b5a08cb25fcac190e6392a4d537)
2022-04-30 12:47:41.341 19404-19404/? A/DEBUG:       #01 pc 000714e7  /data/app/~~3SEksvUnlzRRZpfTUpODAg==/com.example.jnihook-QG30dvAOV5XZBY5UyXtUHg==/lib/arm/libcamelnative.so (BuildId: 3f156414c65658b00d8ab5041aec3d696da4e6b4)
2022-04-30 12:47:41.341 19404-19404/? A/DEBUG:       #02 pc 000714b1  /data/app/~~3SEksvUnlzRRZpfTUpODAg==/com.example.jnihook-QG30dvAOV5XZBY5UyXtUHg==/lib/arm/libcamelnative.so (BuildId: 3f156414c65658b00d8ab5041aec3d696da4e6b4)
2022-04-30 12:47:41.341 19404-19404/? A/DEBUG:       #03 pc 0006e31b  /data/app/~~3SEksvUnlzRRZpfTUpODAg==/com.example.jnihook-QG30dvAOV5XZBY5UyXtUHg==/lib/arm/libcamelnative.so (BuildId: 3f156414c65658b00d8ab5041aec3d696da4e6b4)
2022-04-30 12:47:41.341 19404-19404/? A/DEBUG:       #04 pc 0006e401  /data/app/~~3SEksvUnlzRRZpfTUpODAg==/com.example.jnihook-QG30dvAOV5XZBY5UyXtUHg==/lib/arm/libcamelnative.so (_talloc_reference_loc+44) (BuildId: 3f156414c65658b00d8ab5041aec3d696da4e6b4)
2022-04-30 12:47:41.341 19404-19404/? A/DEBUG:       #05 pc 0006da33  /data/app/~~3SEksvUnlzRRZpfTUpODAg==/com.example.jnihook-QG30dvAOV5XZBY5UyXtUHg==/lib/arm/libcamelnative.so (new_child+942) (BuildId: 3f156414c65658b00d8ab5041aec3d696da4e6b4)
2022-04-30 12:47:41.341 19404-19404/? A/DEBUG:       #06 pc 0006bec3  /data/app/~~3SEksvUnlzRRZpfTUpODAg==/com.example.jnihook-QG30dvAOV5XZBY5UyXtUHg==/lib/arm/libcamelnative.so (handle_tracee_event+1590) (BuildId: 3f156414c65658b00d8ab5041aec3d696da4e6b4)
....

I found a BUG that doesn t know what caused it as if it was a talloc problem.Have you ever encountered this problem? I think it should be wrong with my writing method and I want to fork out a process and go to the attch main process.Because the (enable_syscall_filtering) method parameter needs to wear a tracer。

So I (Tracer * first = get_tracee (NULL, 0, true);)

Initialize in the master process.My code is as follows

void trace_current_process() {
    prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
    pid_t mainPid = getpid();
    pid_t child = fork();
    if (child < 0) {
        ALOGE("ptrace svc  fork() error ")
        return;
    }
    /* Pre-create the first first (pid == 0).  */
    Tracer *first = get_tracee(NULL, mainPid, true);
    if (first == NULL) {
        ALOGE(">>>>>>>>> error: create first first error   ")
        return;
    }
    if (child == 0) {
        // attach main process
        int status = ptrace(PTRACE_ATTACH, mainPid, NULL, NULL);
        if (status != 0) {
            //attch fail
            ALOGE(">>>>>>>>> error: attach target process %d ", status);
            return;
        }

        ALOGE("ptrace main process %d ", child)
        first->wait_sigcont = true;
        first->exe = strdup("zygote");

        upDataForkPid(getpid());

        ALOGE("ptrace attch main sucess ! main pid -> %d  tracer fork pid -> %d", mainPid, getpid())

        exit(event_loop());
    } else {
        //ALOGE("ptrace main process %d ", child)
        //add seccomp by main process
        enable_syscall_filtering(first);
    }
    LOGE("trace_current_process init finsh ")

}

I don't know if I have a problem writing that 。 I wonder if this reason caused the error above