Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,15 @@
#
# Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
# Licensed under the GPL
#
obj-y := clone.o mmu.o process.o syscall.o uaccess.o
# clone.o is in the stub, so it can't be built with profiling
# GCC hardened also auto-enables -fpic, but we need %ebx so it can't work ->
# disable it
CFLAGS_clone.o := $(CFLAGS_NO_HARDENING)
UNPROFILE_OBJS := clone.o
include arch/um/scripts/Makefile.rules

View file

@ -0,0 +1,56 @@
/*
* Copyright (C) 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <signal.h>
#include <sched.h>
#include <asm/unistd.h>
#include <sys/time.h>
#include <as-layout.h>
#include <ptrace_user.h>
#include <stub-data.h>
#include <sysdep/stub.h>
/*
* This is in a separate file because it needs to be compiled with any
* extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled
*
* Use UM_KERN_PAGE_SIZE instead of PAGE_SIZE because that calls getpagesize
* on some systems.
*/
void __attribute__ ((__section__ (".__syscall_stub")))
stub_clone_handler(void)
{
struct stub_data *data = (struct stub_data *) STUB_DATA;
long err;
err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
STUB_DATA + UM_KERN_PAGE_SIZE / 2 - sizeof(void *));
if (err != 0)
goto out;
err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
if (err)
goto out;
err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
(long) &data->timer, 0);
if (err)
goto out;
remap_stack(data->fd, data->offset);
goto done;
out:
/*
* save current result.
* Parent: pid;
* child: retcode of mmap already saved and it jumps around this
* assignment
*/
data->err = err;
done:
trap_myself();
}

178
arch/um/kernel/skas/mmu.c Normal file
View file

@ -0,0 +1,178 @@
/*
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <asm/pgalloc.h>
#include <asm/pgtable.h>
#include <as-layout.h>
#include <os.h>
#include <skas.h>
extern int __syscall_stub_start;
static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
unsigned long kernel)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
pgd = pgd_offset(mm, proc);
pud = pud_alloc(mm, pgd, proc);
if (!pud)
goto out;
pmd = pmd_alloc(mm, pud, proc);
if (!pmd)
goto out_pmd;
pte = pte_alloc_map(mm, NULL, pmd, proc);
if (!pte)
goto out_pte;
*pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
*pte = pte_mkread(*pte);
return 0;
out_pte:
pmd_free(mm, pmd);
out_pmd:
pud_free(mm, pud);
out:
return -ENOMEM;
}
int init_new_context(struct task_struct *task, struct mm_struct *mm)
{
struct mm_context *from_mm = NULL;
struct mm_context *to_mm = &mm->context;
unsigned long stack = 0;
int ret = -ENOMEM;
if (skas_needs_stub) {
stack = get_zeroed_page(GFP_KERNEL);
if (stack == 0)
goto out;
}
to_mm->id.stack = stack;
if (current->mm != NULL && current->mm != &init_mm)
from_mm = &current->mm->context;
if (proc_mm) {
ret = new_mm(stack);
if (ret < 0) {
printk(KERN_ERR "init_new_context_skas - "
"new_mm failed, errno = %d\n", ret);
goto out_free;
}
to_mm->id.u.mm_fd = ret;
}
else {
if (from_mm)
to_mm->id.u.pid = copy_context_skas0(stack,
from_mm->id.u.pid);
else to_mm->id.u.pid = start_userspace(stack);
if (to_mm->id.u.pid < 0) {
ret = to_mm->id.u.pid;
goto out_free;
}
}
ret = init_new_ldt(to_mm, from_mm);
if (ret < 0) {
printk(KERN_ERR "init_new_context_skas - init_ldt"
" failed, errno = %d\n", ret);
goto out_free;
}
return 0;
out_free:
if (to_mm->id.stack != 0)
free_page(to_mm->id.stack);
out:
return ret;
}
void uml_setup_stubs(struct mm_struct *mm)
{
int err, ret;
if (!skas_needs_stub)
return;
ret = init_stub_pte(mm, STUB_CODE,
(unsigned long) &__syscall_stub_start);
if (ret)
goto out;
ret = init_stub_pte(mm, STUB_DATA, mm->context.id.stack);
if (ret)
goto out;
mm->context.stub_pages[0] = virt_to_page(&__syscall_stub_start);
mm->context.stub_pages[1] = virt_to_page(mm->context.id.stack);
/* dup_mmap already holds mmap_sem */
err = install_special_mapping(mm, STUB_START, STUB_END - STUB_START,
VM_READ | VM_MAYREAD | VM_EXEC |
VM_MAYEXEC | VM_DONTCOPY | VM_PFNMAP,
mm->context.stub_pages);
if (err) {
printk(KERN_ERR "install_special_mapping returned %d\n", err);
goto out;
}
return;
out:
force_sigsegv(SIGSEGV, current);
}
void arch_exit_mmap(struct mm_struct *mm)
{
pte_t *pte;
pte = virt_to_pte(mm, STUB_CODE);
if (pte != NULL)
pte_clear(mm, STUB_CODE, pte);
pte = virt_to_pte(mm, STUB_DATA);
if (pte == NULL)
return;
pte_clear(mm, STUB_DATA, pte);
}
void destroy_context(struct mm_struct *mm)
{
struct mm_context *mmu = &mm->context;
if (proc_mm)
os_close_file(mmu->id.u.mm_fd);
else {
/*
* If init_new_context wasn't called, this will be
* zero, resulting in a kill(0), which will result in the
* whole UML suddenly dying. Also, cover negative and
* 1 cases, since they shouldn't happen either.
*/
if (mmu->id.u.pid < 2) {
printk(KERN_ERR "corrupt mm_context - pid = %d\n",
mmu->id.u.pid);
return;
}
os_kill_ptraced_process(mmu->id.u.pid, 1);
}
if (skas_needs_stub)
free_page(mmu->id.stack);
free_ldt(mmu);
}

View file

@ -0,0 +1,81 @@
/*
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <linux/init.h>
#include <linux/sched.h>
#include <as-layout.h>
#include <kern.h>
#include <os.h>
#include <skas.h>
int new_mm(unsigned long stack)
{
int fd, err;
fd = os_open_file("/proc/mm", of_cloexec(of_write(OPENFLAGS())), 0);
if (fd < 0)
return fd;
if (skas_needs_stub) {
err = map_stub_pages(fd, STUB_CODE, STUB_DATA, stack);
if (err) {
os_close_file(fd);
return err;
}
}
return fd;
}
extern void start_kernel(void);
static int __init start_kernel_proc(void *unused)
{
int pid;
block_signals();
pid = os_getpid();
cpu_tasks[0].pid = pid;
cpu_tasks[0].task = current;
#ifdef CONFIG_SMP
init_cpu_online(get_cpu_mask(0));
#endif
start_kernel();
return 0;
}
extern int userspace_pid[];
extern char cpu0_irqstack[];
int __init start_uml(void)
{
stack_protections((unsigned long) &cpu0_irqstack);
set_sigstack(cpu0_irqstack, THREAD_SIZE);
if (proc_mm) {
userspace_pid[0] = start_userspace(0);
if (userspace_pid[0] < 0) {
printf("start_uml - start_userspace returned %d\n",
userspace_pid[0]);
exit(1);
}
}
init_new_thread_signals();
init_task.thread.request.u.thread.proc = start_kernel_proc;
init_task.thread.request.u.thread.arg = NULL;
return start_idle_thread(task_stack_page(&init_task),
&init_task.thread.switch_buf);
}
unsigned long current_stub_stack(void)
{
if (current->mm == NULL)
return 0;
return current->mm->context.id.stack;
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <kern_util.h>
#include <sysdep/ptrace.h>
#include <sysdep/syscalls.h>
extern int syscall_table_size;
#define NR_SYSCALLS (syscall_table_size / sizeof(void *))
void handle_syscall(struct uml_pt_regs *r)
{
struct pt_regs *regs = container_of(r, struct pt_regs, regs);
long result;
int syscall;
syscall_trace_enter(regs);
/*
* This should go in the declaration of syscall, but when I do that,
* strace -f -c bash -c 'ls ; ls' breaks, sometimes not tracing
* children at all, sometimes hanging when bash doesn't see the first
* ls exit.
* The assembly looks functionally the same to me. This is
* gcc version 4.0.1 20050727 (Red Hat 4.0.1-5)
* in case it's a compiler bug.
*/
syscall = UPT_SYSCALL_NR(r);
if ((syscall >= NR_SYSCALLS) || (syscall < 0))
result = -ENOSYS;
else result = EXECUTE_SYSCALL(syscall, regs);
PT_REGS_SET_SYSCALL_RETURN(regs, result);
syscall_trace_leave(regs);
}

View file

@ -0,0 +1,259 @@
/*
* Copyright (C) 2002 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
* Licensed under the GPL
*/
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <asm/current.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <kern_util.h>
#include <os.h>
pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
if (mm == NULL)
return NULL;
pgd = pgd_offset(mm, addr);
if (!pgd_present(*pgd))
return NULL;
pud = pud_offset(pgd, addr);
if (!pud_present(*pud))
return NULL;
pmd = pmd_offset(pud, addr);
if (!pmd_present(*pmd))
return NULL;
return pte_offset_kernel(pmd, addr);
}
static pte_t *maybe_map(unsigned long virt, int is_write)
{
pte_t *pte = virt_to_pte(current->mm, virt);
int err, dummy_code;
if ((pte == NULL) || !pte_present(*pte) ||
(is_write && !pte_write(*pte))) {
err = handle_page_fault(virt, 0, is_write, 1, &dummy_code);
if (err)
return NULL;
pte = virt_to_pte(current->mm, virt);
}
if (!pte_present(*pte))
pte = NULL;
return pte;
}
static int do_op_one_page(unsigned long addr, int len, int is_write,
int (*op)(unsigned long addr, int len, void *arg), void *arg)
{
jmp_buf buf;
struct page *page;
pte_t *pte;
int n, faulted;
pte = maybe_map(addr, is_write);
if (pte == NULL)
return -1;
page = pte_page(*pte);
addr = (unsigned long) kmap_atomic(page) +
(addr & ~PAGE_MASK);
current->thread.fault_catcher = &buf;
faulted = UML_SETJMP(&buf);
if (faulted == 0)
n = (*op)(addr, len, arg);
else
n = -1;
current->thread.fault_catcher = NULL;
kunmap_atomic((void *)addr);
return n;
}
static int buffer_op(unsigned long addr, int len, int is_write,
int (*op)(unsigned long, int, void *), void *arg)
{
int size, remain, n;
size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len);
remain = len;
n = do_op_one_page(addr, size, is_write, op, arg);
if (n != 0) {
remain = (n < 0 ? remain : 0);
goto out;
}
addr += size;
remain -= size;
if (remain == 0)
goto out;
while (addr < ((addr + remain) & PAGE_MASK)) {
n = do_op_one_page(addr, PAGE_SIZE, is_write, op, arg);
if (n != 0) {
remain = (n < 0 ? remain : 0);
goto out;
}
addr += PAGE_SIZE;
remain -= PAGE_SIZE;
}
if (remain == 0)
goto out;
n = do_op_one_page(addr, remain, is_write, op, arg);
if (n != 0) {
remain = (n < 0 ? remain : 0);
goto out;
}
return 0;
out:
return remain;
}
static int copy_chunk_from_user(unsigned long from, int len, void *arg)
{
unsigned long *to_ptr = arg, to = *to_ptr;
memcpy((void *) to, (void *) from, len);
*to_ptr += len;
return 0;
}
int copy_from_user(void *to, const void __user *from, int n)
{
if (segment_eq(get_fs(), KERNEL_DS)) {
memcpy(to, (__force void*)from, n);
return 0;
}
return access_ok(VERIFY_READ, from, n) ?
buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to):
n;
}
EXPORT_SYMBOL(copy_from_user);
static int copy_chunk_to_user(unsigned long to, int len, void *arg)
{
unsigned long *from_ptr = arg, from = *from_ptr;
memcpy((void *) to, (void *) from, len);
*from_ptr += len;
return 0;
}
int copy_to_user(void __user *to, const void *from, int n)
{
if (segment_eq(get_fs(), KERNEL_DS)) {
memcpy((__force void *) to, from, n);
return 0;
}
return access_ok(VERIFY_WRITE, to, n) ?
buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) :
n;
}
EXPORT_SYMBOL(copy_to_user);
static int strncpy_chunk_from_user(unsigned long from, int len, void *arg)
{
char **to_ptr = arg, *to = *to_ptr;
int n;
strncpy(to, (void *) from, len);
n = strnlen(to, len);
*to_ptr += n;
if (n < len)
return 1;
return 0;
}
int strncpy_from_user(char *dst, const char __user *src, int count)
{
int n;
char *ptr = dst;
if (segment_eq(get_fs(), KERNEL_DS)) {
strncpy(dst, (__force void *) src, count);
return strnlen(dst, count);
}
if (!access_ok(VERIFY_READ, src, 1))
return -EFAULT;
n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user,
&ptr);
if (n != 0)
return -EFAULT;
return strnlen(dst, count);
}
EXPORT_SYMBOL(strncpy_from_user);
static int clear_chunk(unsigned long addr, int len, void *unused)
{
memset((void *) addr, 0, len);
return 0;
}
int __clear_user(void __user *mem, int len)
{
return buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL);
}
int clear_user(void __user *mem, int len)
{
if (segment_eq(get_fs(), KERNEL_DS)) {
memset((__force void*)mem, 0, len);
return 0;
}
return access_ok(VERIFY_WRITE, mem, len) ?
buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len;
}
EXPORT_SYMBOL(clear_user);
static int strnlen_chunk(unsigned long str, int len, void *arg)
{
int *len_ptr = arg, n;
n = strnlen((void *) str, len);
*len_ptr += n;
if (n < len)
return 1;
return 0;
}
int strnlen_user(const void __user *str, int len)
{
int count = 0, n;
if (segment_eq(get_fs(), KERNEL_DS))
return strnlen((__force char*)str, len) + 1;
n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count);
if (n == 0)
return count + 1;
return 0;
}
EXPORT_SYMBOL(strnlen_user);