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/exec_emulation.h"
18
19 #include <unistd.h>
20
21 #include <cstring>
22 #include <utility>
23
24 #include "berberis/base/mmap.h"
25 #include "berberis/base/strings.h"
26
27 namespace berberis {
28
29 namespace {
30
GetGuestPlatformVarPrefixWithSize()31 std::pair<const char*, size_t> GetGuestPlatformVarPrefixWithSize() {
32 static constexpr char kGuestPlatformVarPrefix[] = "BERBERIS_GUEST_";
33 return {kGuestPlatformVarPrefix, sizeof(kGuestPlatformVarPrefix) - 1};
34 }
35
IsPlatformVar(const char * s)36 bool IsPlatformVar(const char* s) {
37 return StartsWith(s, "LD_CONFIG_FILE=") || StartsWith(s, "LD_LIBRARY_PATH=") ||
38 StartsWith(s, "LD_DEBUG=") || StartsWith(s, "LD_PRELOAD=");
39 }
40
MangleGuestEnvp(ScopedMmap * dst,char * const * envp)41 char* const* MangleGuestEnvp(ScopedMmap* dst, char* const* envp) {
42 if (envp == nullptr) {
43 return nullptr;
44 }
45
46 int env_count = 0;
47 int text_size = 0;
48 int mangle_count = 0;
49
50 for (;; ++env_count) {
51 char* env = envp[env_count];
52 if (env == nullptr) {
53 break;
54 }
55
56 if (IsPlatformVar(env)) {
57 ++mangle_count;
58 }
59
60 text_size += strlen(env) + 1; // count terminating '\0'
61 }
62
63 if (mangle_count == 0) {
64 return envp;
65 }
66
67 auto [guest_prefix, guest_prefix_size] = GetGuestPlatformVarPrefixWithSize();
68
69 size_t array_size = sizeof(char*) * (env_count + 1); // text pointers + terminating nullptr
70 dst->Init(array_size + text_size + // array + orig text
71 guest_prefix_size * mangle_count); // added prefixes
72
73 char** new_array = static_cast<char**>(dst->data());
74 char* new_text = static_cast<char*>(dst->data()) + array_size;
75
76 for (int i = 0; i < env_count; ++i) {
77 char* env = envp[i];
78 new_array[i] = new_text;
79
80 if (IsPlatformVar(env)) {
81 strcpy(new_text, guest_prefix);
82 new_text += guest_prefix_size;
83 }
84
85 strcpy(new_text, env);
86 new_text += strlen(env) + 1; // count terminating '\0'
87 }
88
89 new_array[env_count] = nullptr; // add terminating nullptr
90
91 return new_array;
92 }
93
94 } // namespace
95
DemangleGuestEnvp(char ** dst,char ** envp)96 char** DemangleGuestEnvp(char** dst, char** envp) {
97 auto [guest_prefix, guest_prefix_size] = GetGuestPlatformVarPrefixWithSize();
98
99 for (; *envp; ++envp) {
100 char* env = *envp;
101 if (IsPlatformVar(env)) {
102 continue;
103 }
104 if (StartsWith(env, guest_prefix) && IsPlatformVar(env + guest_prefix_size)) {
105 env += guest_prefix_size;
106 }
107 *dst++ = env;
108 }
109
110 *dst++ = nullptr;
111 return dst;
112 }
113
ExecveForGuest(const char * filename,char * const argv[],char * const envp[])114 int ExecveForGuest(const char* filename, char* const argv[], char* const envp[]) {
115 ScopedMmap new_envp;
116 return execve(filename, argv, MangleGuestEnvp(&new_envp, envp));
117 }
118
119 } // namespace berberis
120