diff options
| author | Po Lu | 2024-07-02 12:10:43 +0800 |
|---|---|---|
| committer | Po Lu | 2024-07-02 12:12:14 +0800 |
| commit | 6b5accdc05d007ab4d1804865c1b043260006673 (patch) | |
| tree | 0c7909756b47cd524a397becb766ef8452cd85fa /exec | |
| parent | e087d3009bf564446367a1465957d9ea7b699f01 (diff) | |
| download | emacs-6b5accdc05d007ab4d1804865c1b043260006673.tar.gz emacs-6b5accdc05d007ab4d1804865c1b043260006673.zip | |
Port seccomp acceleration to Linux 3.5.0
* etc/NEWS: Update correspondingly.
* exec/Makefile.in (config-mips.m4): Don't define rule
or predicate $(LOADOBJS) on it elsewhere than on MIPS.
* exec/README: Direct developers to GDB.
* exec/trace.c (finish_exec): Resume the tracee after reporting
an error in `exec'.
(after_fork): If seccomp is enabled on Android, and the kernel
is 4.7 or earlier, detect whether revisions to the sequencing of
seccomp events have been backported from 4.8.
(exec_waitpid): Resume the process with PTRACE_CONT after
receiving an unknown signal.
(exec_init): Cease disabling seccomp on Android kernels earlier
than 4.8.
Diffstat (limited to 'exec')
| -rw-r--r-- | exec/Makefile.in | 8 | ||||
| -rw-r--r-- | exec/README | 3 | ||||
| -rw-r--r-- | exec/trace.c | 113 |
3 files changed, 98 insertions, 26 deletions
diff --git a/exec/Makefile.in b/exec/Makefile.in index 6969039b0a4..7e681c0c3d8 100644 --- a/exec/Makefile.in +++ b/exec/Makefile.in | |||
| @@ -90,16 +90,16 @@ ifeq ($(is_mips),yes) | |||
| 90 | .s.o: | 90 | .s.o: |
| 91 | $(M4) $< > $(notdir $<).s | 91 | $(M4) $< > $(notdir $<).s |
| 92 | $(AS) $(ASFLAGS) $(notdir $<).s -o $@ | 92 | $(AS) $(ASFLAGS) $(notdir $<).s -o $@ |
| 93 | else | ||
| 94 | .s.o: | ||
| 95 | $(AS) $(ASFLAGS) $< -o $@ | ||
| 96 | endif | ||
| 97 | 93 | ||
| 98 | # Set up dependencies for config-mips.m4. | 94 | # Set up dependencies for config-mips.m4. |
| 99 | 95 | ||
| 100 | config-mips.m4: config-mips.m4.in | 96 | config-mips.m4: config-mips.m4.in |
| 101 | cd $(srcdir) && ./config.status $@ | 97 | cd $(srcdir) && ./config.status $@ |
| 102 | $(LOADOBJS): config-mips.m4 | 98 | $(LOADOBJS): config-mips.m4 |
| 99 | else | ||
| 100 | .s.o: | ||
| 101 | $(AS) $(ASFLAGS) $< -o $@ | ||
| 102 | endif | ||
| 103 | 103 | ||
| 104 | # Set up rules to build libexec.a. | 104 | # Set up rules to build libexec.a. |
| 105 | 105 | ||
diff --git a/exec/README b/exec/README index f7eb21cfc84..a1534503247 100644 --- a/exec/README +++ b/exec/README | |||
| @@ -1,3 +1,6 @@ | |||
| 1 | This directory holds the source code to a library used to replace the | 1 | This directory holds the source code to a library used to replace the |
| 2 | `execve' and `execveat' system calls, used by the Android port of | 2 | `execve' and `execveat' system calls, used by the Android port of |
| 3 | Emacs to start executables without intervention from the system. | 3 | Emacs to start executables without intervention from the system. |
| 4 | |||
| 5 | The most edifying resource for developers will be GDB, or to be precise, | ||
| 6 | the Linux target implementations for architectures of interest. | ||
diff --git a/exec/trace.c b/exec/trace.c index dfbc255a894..2af6d867efe 100644 --- a/exec/trace.c +++ b/exec/trace.c | |||
| @@ -845,7 +845,12 @@ finish_exec (struct exec_tracee *tracee, USER_REGS_STRUCT *regs) | |||
| 845 | #else /* !__aarch64__ */ | 845 | #else /* !__aarch64__ */ |
| 846 | ptrace (PTRACE_SETREGS, tracee->pid, NULL, regs); | 846 | ptrace (PTRACE_SETREGS, tracee->pid, NULL, regs); |
| 847 | #endif /* __aarch64__ */ | 847 | #endif /* __aarch64__ */ |
| 848 | return; | 848 | |
| 849 | /* Continue; not much in the way of remediation is available if | ||
| 850 | either of PTRACE_SETREGS and this resumption fails. */ | ||
| 851 | ptrace ((use_seccomp_p ? PTRACE_CONT : PTRACE_SYSCALL), | ||
| 852 | tracee->pid, 0, 0); | ||
| 853 | goto error; | ||
| 849 | } | 854 | } |
| 850 | 855 | ||
| 851 | /* Write the loader area to the stack, followed by its size and the | 856 | /* Write the loader area to the stack, followed by its size and the |
| @@ -1858,6 +1863,10 @@ after_fork (pid_t pid) | |||
| 1858 | { | 1863 | { |
| 1859 | int wstatus, rc, flags; | 1864 | int wstatus, rc, flags; |
| 1860 | struct exec_tracee *tracee; | 1865 | struct exec_tracee *tracee; |
| 1866 | #if defined HAVE_SECCOMP && __ANDROID__ | ||
| 1867 | int statusarg; | ||
| 1868 | USER_REGS_STRUCT regs; | ||
| 1869 | #endif /* defined HAVE_SECCOMP && __ANDROID__ */ | ||
| 1861 | 1870 | ||
| 1862 | /* First, wait for something to happen to PID. */ | 1871 | /* First, wait for something to happen to PID. */ |
| 1863 | again: | 1872 | again: |
| @@ -1897,14 +1906,86 @@ after_fork (pid_t pid) | |||
| 1897 | return 1; | 1906 | return 1; |
| 1898 | } | 1907 | } |
| 1899 | 1908 | ||
| 1900 | /* Request that the child stop upon the next system call, or the next | 1909 | #if defined HAVE_SECCOMP && __ANDROID__ |
| 1901 | filter event. */ | 1910 | /* Certain Android kernels have received backports of those new |
| 1902 | rc = ptrace ((use_seccomp_p ? PTRACE_CONT : PTRACE_SYSCALL), | 1911 | PTRACE_EVENT_SECCOMP semantics which were introduced in kernel |
| 1903 | pid, 0, 0); | 1912 | version 4.8, so that it is necessary to actively establish which |
| 1913 | variant is in place. */ | ||
| 1914 | |||
| 1915 | if (kernel_4_7_or_earlier && use_seccomp_p) | ||
| 1916 | { | ||
| 1917 | /* Request that the child stop upon the next `exec' system call, | ||
| 1918 | one of which is assumed to always be issued by the child, as | ||
| 1919 | below, but await the next stop, and examine its contents. | ||
| 1920 | Anciently, the syscall-stop preceeded events marked | ||
| 1921 | PTRACE_EVENT_SECCOMP, whereas this sequence is reversed in | ||
| 1922 | 4.8+, and in releases with these changes backported. */ | ||
| 1923 | |||
| 1924 | rc = ptrace (PTRACE_SYSCALL, pid, 0, 0); | ||
| 1925 | if (rc) | ||
| 1926 | return 1; | ||
| 1927 | |||
| 1928 | while (true) | ||
| 1929 | { | ||
| 1930 | rc = waitpid (pid, &wstatus, __WALL); | ||
| 1931 | if (rc != pid) | ||
| 1932 | return 1; | ||
| 1933 | |||
| 1934 | if (WIFSTOPPED (wstatus)) | ||
| 1935 | { | ||
| 1936 | /* Verify that this system call is `exec', not one issued | ||
| 1937 | between PTRACE_TRACEME and `exec' intercepted by | ||
| 1938 | PTRACE_SYSCALL. */ | ||
| 1939 | #ifdef __aarch64__ | ||
| 1940 | rc = aarch64_get_regs (pid, ®s); | ||
| 1941 | #else /* !__aarch64__ */ | ||
| 1942 | rc = ptrace (PTRACE_GETREGS, pid, NULL, ®s); | ||
| 1943 | #endif /* __aarch64__ */ | ||
| 1944 | if (rc) | ||
| 1945 | return 1; | ||
| 1946 | |||
| 1947 | if (regs.SYSCALL_NUM_REG == EXEC_SYSCALL) | ||
| 1948 | { | ||
| 1949 | statusarg = ((wstatus & 0xfff00) >> 8); | ||
| 1950 | |||
| 1951 | if (statusarg == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) | ||
| 1952 | { | ||
| 1953 | /* The first event to be delivered is a seccomp | ||
| 1954 | stop, indicating that this is an unmodified | ||
| 1955 | <4.7 kernel. Return to await the subsequent | ||
| 1956 | syscall-stop, which should be received and | ||
| 1957 | acted on by process_system_call. */ | ||
| 1958 | rc = ptrace (PTRACE_SYSCALL, pid, 0, 0); | ||
| 1959 | break; | ||
| 1960 | } | ||
| 1961 | else if (statusarg == (SIGTRAP | 0x80)) | ||
| 1962 | { | ||
| 1963 | /* Syscall-traps take priority. This is a | ||
| 1964 | doctored 4.7 kernel. */ | ||
| 1965 | kernel_4_7_or_earlier = false; | ||
| 1966 | rc = ptrace (PTRACE_CONT, pid, 0, 0); | ||
| 1967 | break; | ||
| 1968 | } | ||
| 1969 | } | ||
| 1970 | |||
| 1971 | rc = ptrace (PTRACE_SYSCALL, pid, 0, 0); | ||
| 1972 | if (rc) | ||
| 1973 | return 1; | ||
| 1974 | } | ||
| 1975 | else | ||
| 1976 | return 1; | ||
| 1977 | } | ||
| 1978 | } | ||
| 1979 | else | ||
| 1980 | #endif /* HAVE_SECCOMP && __ANDROID__ */ | ||
| 1981 | /* Request that the child stop upon the next system call, or the | ||
| 1982 | next filter event. */ | ||
| 1983 | rc = ptrace ((use_seccomp_p ? PTRACE_CONT : PTRACE_SYSCALL), | ||
| 1984 | pid, 0, 0); | ||
| 1904 | if (rc) | 1985 | if (rc) |
| 1905 | return 1; | 1986 | return 1; |
| 1906 | 1987 | ||
| 1907 | /* Enter the child in `tracing_processes'. */ | 1988 | /* Enroll the child into `tracing_processes'. */ |
| 1908 | 1989 | ||
| 1909 | if (free_tracees) | 1990 | if (free_tracees) |
| 1910 | { | 1991 | { |
| @@ -2064,8 +2145,9 @@ exec_waitpid (pid_t pid, int *wstatus, int options) | |||
| 2064 | #endif /* SIGSYS */ | 2145 | #endif /* SIGSYS */ |
| 2065 | 2146 | ||
| 2066 | default: | 2147 | default: |
| 2067 | /* Continue the process until the next syscall. */ | 2148 | /* Resume the process as appropriate. */ |
| 2068 | ptrace (PTRACE_SYSCALL, pid, 0, status); | 2149 | ptrace ((use_seccomp_p ? PTRACE_CONT : PTRACE_SYSCALL), |
| 2150 | pid, 0, status); | ||
| 2069 | return -1; | 2151 | return -1; |
| 2070 | } | 2152 | } |
| 2071 | } | 2153 | } |
| @@ -2117,20 +2199,7 @@ exec_init (const char *loader) | |||
| 2117 | else | 2199 | else |
| 2118 | { | 2200 | { |
| 2119 | if (major < 4 || (major == 4 && minor <= 7)) | 2201 | if (major < 4 || (major == 4 && minor <= 7)) |
| 2120 | { | 2202 | kernel_4_7_or_earlier = true; |
| 2121 | #ifndef __ANDROID__ | ||
| 2122 | kernel_4_7_or_earlier = true; | ||
| 2123 | #else /* __ANDROID __ */ | ||
| 2124 | /* Certain Android kernels have received backports of | ||
| 2125 | those new PTRACE_EVENT_SECCOMP semantics which were | ||
| 2126 | introduced in kernel version 4.8, so that it is | ||
| 2127 | necessary to actively establish which variant is in | ||
| 2128 | place. This being much too involved for code I cannot | ||
| 2129 | test, simply disable seccomp on kernel releases subject | ||
| 2130 | to these uncertainties. */ | ||
| 2131 | use_seccomp_p = false; | ||
| 2132 | #endif /* !__ANDROID__ */ | ||
| 2133 | } | ||
| 2134 | } | 2203 | } |
| 2135 | } | 2204 | } |
| 2136 | #endif /* HAVE_SECCOMP */ | 2205 | #endif /* HAVE_SECCOMP */ |