this repo has no description
1/*
2 * This file is part of Darling.
3 * Copyright (C) 2021 Darling developers
4 *
5 * Originally part of the Darling Mach Linux Kernel Module
6 * Copyright (C) 2017 Lubos Dolezel
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 */
22
23#include <stddef.h>
24#include <string.h>
25#include <unistd.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include "loader.h"
29#include <darling-config.h>
30#include "elfcalls/elfcalls.h"
31
32#if defined(GEN_64BIT)
33#define FUNCTION_NAME setup_stack64
34#define user_long_t unsigned long
35#elif defined(GEN_32BIT)
36#define FUNCTION_NAME setup_stack32
37#define user_long_t unsigned int
38#else
39#error See above
40#endif
41
42#define __user
43
44#define EXECUTABLE_PATH "executable_path="
45
46#define __put_user(value, pointer) ({ \
47 __typeof__(value) _tmpval = (value); \
48 memcpy((pointer), &_tmpval, sizeof(_tmpval)); \
49 0; \
50 })
51
52void elfcalls_make(struct elf_calls* calls);
53
54static struct elf_calls _elfcalls;
55
56void FUNCTION_NAME(const char* filepath, struct load_results* lr)
57{
58 int err = 0;
59 // unsigned char rand_bytes[16];
60 char *executable_path;
61 static char executable_buf[4096];
62 user_long_t __user* argv;
63 user_long_t __user* envp;
64 user_long_t __user* applep;
65 user_long_t __user* sp;
66 char __user* exepath_user;
67 size_t exepath_len;
68 char __user* kernfd_user;
69 char kernfd[12];
70 char __user* elfcalls_user;
71 char elfcalls[27];
72 char __user* applep_contents[4];
73
74#define user_long_count(_val) (((_val) + (sizeof(user_long_t) - 1)) / sizeof(user_long_t))
75
76 elfcalls_make(&_elfcalls);
77
78 // Produce executable_path=... for applep
79 executable_buf[sizeof(executable_buf) - 1] = '\0';
80 strncpy(executable_buf, filepath, 4096);
81 if (executable_buf[sizeof(executable_buf) - 1] != '\0')
82 {
83 fprintf(stderr, "File path was too big\n");
84 exit(1);
85 }
86
87 executable_path = executable_buf;
88
89 if (lr->root_path)
90 {
91 exepath_len = strlen(executable_path);
92
93 if (strncmp(executable_path, lr->root_path, lr->root_path_length) == 0)
94 {
95 memmove(executable_buf, executable_path + lr->root_path_length, exepath_len - lr->root_path_length + 1);
96 }
97 else
98 {
99 // FIXME: potential buffer overflow
100 memmove(executable_buf + sizeof(SYSTEM_ROOT) - 1, executable_path, exepath_len + 1);
101 memcpy(executable_buf, SYSTEM_ROOT, sizeof(SYSTEM_ROOT) - 1);
102 }
103 executable_path = executable_buf;
104 }
105
106 // printk(KERN_NOTICE "Stack top: %p\n", bprm->p);
107 exepath_len = strlen(executable_path);
108 sp = (user_long_t*) (lr->stack_top & ~(sizeof(user_long_t)-1));
109
110 // 1 pointer for the mach header
111 // 1 user_long_t for the argument count
112 // `argc`-count pointers for arguments (+1 for NULL)
113 // `envc`-count pointers for env vars (+1 for NULL)
114 // `sizeof(applep_contents) / sizeof(*applep_contents)`-count pointers for applep arguments (already includes NULL)
115 // space for exepath, kernfd, and elfcalls
116 sp -= 1 + 1 + (lr->argc + 1) + (lr->envc + 1) + (sizeof(applep_contents) / sizeof(*applep_contents)) + user_long_count(exepath_len + sizeof(EXECUTABLE_PATH) + sizeof(kernfd) + sizeof(elfcalls));
117
118 exepath_user = (char __user*) lr->stack_top - exepath_len - sizeof(EXECUTABLE_PATH);
119 memcpy(exepath_user, EXECUTABLE_PATH, sizeof(EXECUTABLE_PATH)-1);
120 memcpy(exepath_user + sizeof(EXECUTABLE_PATH)-1, executable_path, exepath_len + 1);
121
122 snprintf(kernfd, sizeof(kernfd), "kernfd=%d", lr->kernfd);
123 kernfd_user = exepath_user - sizeof(kernfd);
124 memcpy(kernfd_user, kernfd, sizeof(kernfd));
125
126#if defined(GEN_64BIT)
127 #define POINTER_FORMAT "%lx"
128#elif defined(GEN_32BIT)
129 #define POINTER_FORMAT "%x"
130#endif
131
132 snprintf(elfcalls, sizeof(elfcalls), "elf_calls=" POINTER_FORMAT, (unsigned long)(uintptr_t)&_elfcalls);
133 elfcalls_user = kernfd_user - sizeof(elfcalls);
134 memcpy(elfcalls_user, elfcalls, sizeof(elfcalls));
135
136 applep_contents[0] = exepath_user;
137 applep_contents[1] = kernfd_user;
138 applep_contents[2] = elfcalls_user;
139 applep_contents[3] = NULL;
140
141 lr->stack_top = (unsigned long) sp;
142
143 // XXX: skip this for static executables, but we don't support them anyway...
144 if (__put_user((user_long_t) lr->mh, sp++))
145 {
146 fprintf(stderr, "Failed to copy mach header address to stack\n");
147 exit(1);
148 }
149 if (__put_user((user_long_t) lr->argc, sp++))
150 {
151 fprintf(stderr, "Failed to copy argument count to stack\n");
152 exit(1);
153 }
154
155 // Fill in argv pointers
156 argv = sp;
157 for (int i = 0; i < lr->argc; ++i)
158 {
159 if (!lr->argv[i]) {
160 lr->argc = i;
161 break;
162 }
163 if (__put_user((user_long_t) lr->argv[i], argv++))
164 {
165 fprintf(stderr, "Failed to copy an argument pointer to stack\n");
166 exit(1);
167 }
168 }
169 if (__put_user((user_long_t) 0, argv++))
170 {
171 fprintf(stderr, "Failed to null-terminate the argument pointer array\n");
172 exit(1);
173 }
174
175 // Fill in envp pointers
176 envp = argv;
177 for (int i = 0; i < lr->envc; ++i)
178 {
179 if (!lr->envp[i]) {
180 lr->envc = i;
181 break;
182 }
183
184 if (__put_user((user_long_t) lr->envp[i], envp++))
185 {
186 fprintf(stderr, "Failed to copy an environment variable pointer to stack\n");
187 exit(1);
188 }
189 }
190 if (__put_user((user_long_t) 0, envp++))
191 {
192 fprintf(stderr, "Failed to null-terminate the environment variable pointer array\n");
193 exit(1);
194 }
195
196 applep = envp; // envp is now at the end of env pointers
197
198 for (int i = 0; i < sizeof(applep_contents)/sizeof(applep_contents[0]); i++)
199 {
200 if (__put_user((user_long_t)(unsigned long) applep_contents[i], applep++))
201 {
202 fprintf(stderr, "Failed to copy an applep value to stack\n");
203 exit(1);
204 }
205 }
206
207 // get_random_bytes(rand_bytes, sizeof(rand_bytes));
208
209 // TODO: produce stack_guard, e.g. stack_guard=0xcdd5c48c061b00fd (must contain 00 somewhere!)
210 // TODO: produce malloc_entropy, e.g. malloc_entropy=0x9536cc569d9595cf,0x831942e402da316b
211 // TODO: produce main_stack?
212}
213
214#undef FUNCTION_NAME
215#undef user_long_t