/ src / startup / mldr / stack.c
stack.c
  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  
 52  void elfcalls_make(struct elf_calls* calls);
 53  
 54  static struct elf_calls _elfcalls;
 55  
 56  void 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