1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "berberis/kernel_api/sys_ptrace_emulation.h"
18 
19 #include <sys/ptrace.h>
20 #include <sys/syscall.h>
21 #include <sys/uio.h>
22 #include <unistd.h>
23 
24 #include <cerrno>
25 #include <cstring>
26 
27 #include "berberis/kernel_api/tracing.h"
28 
29 namespace berberis {
30 
PtraceForGuest(int int_request,pid_t pid,void * addr,void * data)31 int PtraceForGuest(int int_request, pid_t pid, void* addr, void* data) {
32 #if defined(__BIONIC__)
33   using RequestType = int;
34 #elif defined(__GLIBC__)
35   using RequestType = enum __ptrace_request;
36 #elif defined(ANDROID_HOST_MUSL)
37   using RequestType = int;
38 #else
39 #error "Unsupported libc"
40 #endif
41 
42   auto request = static_cast<RequestType>(int_request);
43 
44   auto [processed, result] = PtraceForGuestArch(int_request, pid, addr, data);
45   if (processed) {
46     return result;
47   }
48 
49   switch (int_request) {
50     case PTRACE_TRACEME:
51       return ptrace(PTRACE_TRACEME);
52     case PTRACE_INTERRUPT:
53     case PTRACE_ATTACH:
54       return ptrace(request, pid, 0, 0);
55     case PTRACE_SEIZE:
56     case PTRACE_DETACH:
57     case PTRACE_CONT:
58     case PTRACE_SETOPTIONS:
59       return ptrace(request, pid, 0, data);
60     case PTRACE_PEEKDATA:
61     case PTRACE_PEEKTEXT: {
62       // ATTENTION: Syscall API for these calls is different from libc wrappers!
63       // The syscall stores the requested value at *data, and returns error status
64       // as the result.
65       return syscall(__NR_ptrace, request, pid, addr, data);
66     }
67     case PTRACE_POKEDATA:
68     case PTRACE_POKETEXT:
69       return ptrace(request, pid, addr, data);
70     case PTRACE_GETSIGINFO:
71       KAPI_TRACE("not implemented: ptrace(PTRACE_GETSIGINFO, ...)");
72       errno = EPERM;
73       return -1;
74     case PTRACE_GETREGSET:
75       KAPI_TRACE("not implemented: ptrace(PTRACE_GETREGSET, ...)");
76       if (data) {
77         // Even in case of error, kernel sets iov_len to amount of data written.
78         auto iov = reinterpret_cast<iovec*>(data);
79         iov->iov_len = 0;
80         errno = EINVAL;
81       } else {
82         errno = EFAULT;
83       }
84       return -1;
85     case PTRACE_SETREGSET:
86       KAPI_TRACE("not implemented: ptrace(PTRACE_SETREGSET, ...)");
87       errno = EINVAL;
88       return -1;
89     default:
90       KAPI_TRACE("not implemented: ptrace(0x%x, ...)", request);
91       errno = EPERM;
92       return -1;
93   }
94 }
95 
96 }  // namespace berberis
97