1 /*
2  * Copyright (C) 2023 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 #ifndef BERBERIS_GUEST_OS_PRIMITIVES_GUEST_THREAD_H_
18 #define BERBERIS_GUEST_OS_PRIMITIVES_GUEST_THREAD_H_
19 
20 #include <csetjmp>  // jmp_buf
21 #include <csignal>  // stack_t
22 #include <memory>
23 
24 #include "berberis/guest_state/guest_addr.h"
25 #include "berberis/guest_state/guest_state_opaque.h"
26 #include "berberis/runtime_primitives/signal_queue.h"
27 
28 struct NativeBridgeStaticTlsConfig;
29 
30 namespace berberis {
31 
32 class GuestSignalActionsTable;
33 
34 int CreateNewGuestThread(pthread_t* thread_id,
35                          const pthread_attr_t* attr,
36                          void* guest_stack,
37                          size_t guest_stack_size,
38                          size_t guest_guard_size,
39                          GuestAddr func,
40                          GuestAddr arg);
41 
42 pid_t CloneGuestThread(GuestThread* thread,
43                        int flags,
44                        GuestAddr guest_stack_top,
45                        GuestAddr parent_tid,
46                        GuestAddr new_tls,
47                        GuestAddr child_tid);
48 
49 struct GuestArgumentBuffer;
50 void RunGuestPthreadKeyDtor(GuestAddr pc, GuestArgumentBuffer* buf);
51 
52 struct GuestCallExecution {
53   GuestCallExecution* parent = nullptr;
54   GuestAddr sp = {};
55   jmp_buf buf;
56 };
57 
58 // ATTENTION: GuestThread object can only be used by the current thread!
59 class GuestThread {
60  public:
61   static GuestThread* CreatePthread(void* stack, size_t stack_size, size_t guard_size);
62   static GuestThread* CreateClone(const GuestThread* parent, bool share_signal_actions);
63   static GuestThread* CreateForTest(ThreadState* state);
64   static void Destroy(GuestThread* thread);
65   static void Exit(GuestThread* thread, int status);
66 
67   // Initialize *current* guest thread.
68   void InitStaticTls();
69 
70   // Configure static tls for *current* *main* guest thread.
71   void ConfigStaticTls(const NativeBridgeStaticTlsConfig* config);
72 
73   void ProcessPendingSignals();
74 
75   // Both return *previous* pending signals status (false: disabled, true: enabled).
76   bool ProcessAndDisablePendingSignals();
77   bool TestAndEnablePendingSignals();
78 
79   void SetSignalFromHost(const siginfo_t& info);
80 
GetAttr(GuestAddr * stack_base,size_t * stack_size,size_t * guard_size)81   void GetAttr(GuestAddr* stack_base, size_t* stack_size, size_t* guard_size) const {
82     *stack_base = ToGuestAddr(stack_);
83     *stack_size = stack_size_;
84     *guard_size = guard_size_;
85   }
86 
state()87   const ThreadState* state() const { return state_; }
state()88   ThreadState* state() { return state_; }
89 
guest_call_execution()90   GuestCallExecution* guest_call_execution() const { return guest_call_execution_; }
set_guest_call_execution(GuestCallExecution * guest_call_execution)91   void set_guest_call_execution(GuestCallExecution* guest_call_execution) {
92     guest_call_execution_ = guest_call_execution;
93   }
94 
95   bool SigAltStack(const stack_t* ss, stack_t* old_ss, int* error);
96   void SwitchToSigAltStack();
97   bool IsOnSigAltStack() const;
98 
DisallowStackUnmap()99   void DisallowStackUnmap() { mmap_size_ = 0; }
GetStackTop()100   [[nodiscard]] GuestAddr GetStackTop() const { return stack_top_; }
101 
102   // TODO(b/156271630): Refactor to make this private.
103   void* GetHostStackTop() const;
104 
GetSignalActionsTable()105   [[nodiscard]] GuestSignalActionsTable* GetSignalActionsTable() { return signal_actions_.get(); }
106   // Use to unshare signal handlers for CLONE_VM without CLONE_SIGHAND.
107   void CloneSignalActionsTableFrom(GuestSignalActionsTable* from_table);
108 
109  private:
110   GuestThread() = default;
111   static GuestThread* Create();
112 
113   bool AllocStack(void* stack, size_t stack_size, size_t guard_size);
114   bool AllocShadowCallStack();
115   bool AllocStaticTls();
116 
117   void ProcessPendingSignalsImpl();
118 
119   // Set the default table for the main process.
120   void SetDefaultSignalActionsTable();
121 
122   // Host stack. Valid for cloned threads only.
123   void* host_stack_ = nullptr;
124 
125   // Stack.
126   void* stack_ = nullptr;
127   size_t stack_size_ = 0;
128   size_t guard_size_ = 0;
129   size_t mmap_size_ = 0;
130   GuestAddr stack_top_ = {};
131 
132   void* static_tls_ = nullptr;
133 
134   // Shadow call stack.
135   void* scs_region_ = nullptr;
136   GuestAddr scs_base_ = {};
137 
138   ThreadState* state_ = nullptr;
139 
140   SignalQueue pending_signals_;
141   // When created with CreateClone guest threads either share or fork signal handlers
142   // from the parent. We implement this using shared_ptr semantics.
143   // When created with CreatePthread guest threads use the default global handlers,
144   // which we should never delete. So we create shared_ptr with void deleter in this case.
145   std::shared_ptr<GuestSignalActionsTable> signal_actions_;
146 
147   GuestCallExecution* guest_call_execution_ = nullptr;
148 
149   void* sig_alt_stack_ = nullptr;
150   size_t sig_alt_stack_size_ = 0;
151 };
152 
153 }  // namespace berberis
154 
155 #endif  // BERBERIS_GUEST_OS_PRIMITIVES_GUEST_THREAD_H_
156