M2-Mesoplanet/cc_spawn.c

490 lines
13 KiB
C
Raw Normal View History

2021-11-23 00:53:12 +00:00
/* Copyright (C) 2016 Jeremiah Orians
* Copyright (C) 2020 deesix <deesix@tuta.io>
* This file is part of M2-Planet.
*
* M2-Planet is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* M2-Planet is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with M2-Planet. If not, see <http://www.gnu.org/licenses/>.
*/
#include"cc.h"
#include <unistd.h>
#include <sys/wait.h>
#define MAX_ARRAY 256
char* env_lookup(char* variable);
/* Function to find a character in a string */
char* find_char(char* string, char a)
{
if(0 == string[0])
{
return NULL;
}
while(a != string[0])
{
string = string + 1;
if(0 == string[0])
{
return string;
}
}
return string;
}
/* Find the full path to an executable */
char* find_executable(char* name)
{
char* PATH = env_lookup("PATH");
require(NULL != PATH, "No PATH found\nAborting\n");
2021-11-23 00:53:12 +00:00
if(match("", name))
{
return NULL;
}
if(('.' == name[0]) || ('/' == name[0]))
{
/* assume names that start with . or / are relative or absolute */
return name;
}
char* trial = calloc(MAX_STRING, sizeof(char));
char* MPATH = calloc(MAX_STRING, sizeof(char)); /* Modified PATH */
require(MPATH != NULL, "Memory initialization of MPATH in find_executable failed\n");
strcpy(MPATH, PATH);
FILE* t;
char* next = find_char(MPATH, ':');
int index;
int offset;
int mpath_length;
int name_length;
int trial_length;
while(NULL != next)
{
/* Reset trial */
trial_length = strlen(trial);
for(index = 0; index < trial_length; index = index + 1)
{
trial[index] = 0;
}
next[0] = 0;
/* prepend_string(MPATH, prepend_string("/", name)) */
mpath_length = strlen(MPATH);
for(index = 0; index < mpath_length; index = index + 1)
{
require(MAX_STRING > index, "Element of PATH is too long\n");
trial[index] = MPATH[index];
}
trial[index] = '/';
offset = strlen(trial);
name_length = strlen(name);
for(index = 0; index < name_length; index = index + 1)
{
require(MAX_STRING > index, "Element of PATH is too long\n");
trial[index + offset] = name[index];
}
/* Try the trial */
trial_length = strlen(trial);
require(trial_length < MAX_STRING, "COMMAND TOO LONG!\nABORTING HARD\n");
t = fopen(trial, "r");
if(NULL != t)
{
fclose(t);
return trial;
}
MPATH = next + 1;
next = find_char(MPATH, ':');
}
return NULL;
}
2021-11-23 10:58:45 +00:00
void sanity_command_check(char** array)
{
int i = 0;
char* s = array[0];
while(NULL != s)
{
fputs(s, stderr);
fputc(' ', stderr);
i = i + 1;
s = array[i];
}
fputc('\n', stderr);
}
int what_exit(char* program, int status)
{
/***********************************************************************************
* If the low-order 8 bits of w_status are equal to 0x7F or zero, the child *
* process has stopped. If the low-order 8 bits of w_status are non-zero and are *
* not equal to 0x7F, the child process terminated due to a signal otherwise, the *
* child process terminated due to an exit() call. *
* *
* In the event it was a signal that stopped the process the top 8 bits of *
* w_status contain the signal that caused the process to stop. *
* *
* In the event it was terminated the bottom 7 bits of w_status contain the *
* terminating error number for the process. *
* *
* If bit 0x80 of w_status is set, a core dump was produced. *
***********************************************************************************/
2022-01-24 23:45:13 +00:00
if(DEBUG_LEVEL > 6)
{
fputs("in what_exit with char* program of: ", stderr);
fputs(program, stderr);
fputs("\nAnd int status of: 0x", stderr);
fputs(int2str(status, 16, FALSE), stderr);
fputc('\n', stderr);
}
int WIFEXITED = !(status & 0x7F);
int WEXITSTATUS = (status & 0xFF00) >> 8;
int WTERMSIG = status & 0x7F;
int WCOREDUMP = status & 0x80;
int WIFSIGNALED = !((0x7F == WTERMSIG) || (0 == WTERMSIG));
int WIFSTOPPED = ((0x7F == WTERMSIG) && (0 == WCOREDUMP));
if(WIFEXITED)
{
if(DEBUG_LEVEL > 2)
{
fputc('\n', stderr);
fputs(program, stderr);
fputs(" normal termination, exit status = ", stderr);
fputs(int2str(WEXITSTATUS, 10, TRUE), stderr);
fputc('\n', stderr);
}
return WEXITSTATUS;
}
else if (WIFSIGNALED)
{
fputc('\n', stderr);
fputs(program, stderr);
fputs(" abnormal termination, signal number = ", stderr);
fputs(int2str(WTERMSIG, 10, TRUE), stderr);
fputc('\n', stderr);
if(WCOREDUMP) fputs("core dumped\n", stderr);
return WTERMSIG;
}
else if(WIFSTOPPED)
{
fputc('\n', stderr);
fputs(program, stderr);
fputs(" child stopped, signal number = ", stderr);
fputs(int2str(WEXITSTATUS, 10, TRUE), stderr);
fputc('\n', stderr);
return WEXITSTATUS;
}
fputc('\n', stderr);
fputs(program, stderr);
fputs(" :: something crazy happened with execve\nI'm just gonna get the hell out of here\n", stderr);
exit(EXIT_FAILURE);
}
void _execute(char* name, char** array, char** envp)
2021-11-23 00:53:12 +00:00
{
int status; /* i.e. return code */
/* Get the full path to the executable */
char* program = find_executable(name);
/* Check we can find the executable */
if(NULL == program)
{
fputs("WHILE EXECUTING ", stderr);
fputs(name, stderr);
fputs(" NOT FOUND!\nABORTING HARD\n", stderr);
exit(EXIT_FAILURE);
}
2021-11-23 10:58:45 +00:00
sanity_command_check(array);
2022-12-26 17:04:28 +00:00
int result;
#ifdef __uefi__
result = spawn(program, array, envp);
#else
2021-11-23 00:53:12 +00:00
int f = fork();
/* Ensure fork succeeded */
if(f == -1)
{
fputs("WHILE EXECUTING ", stderr);
fputs(name, stderr);
fputs("fork() FAILED\nABORTING HARD\n", stderr);
exit(EXIT_FAILURE);
}
else if(f == 0)
{
/* Child */
/**************************************************************
* Fuzzing produces random stuff; we don't want it running *
* dangerous commands. So we just don't execve. *
**************************************************************/
if(FALSE == FUZZING)
{
/* We are not fuzzing */
/* execve() returns only on error */
execve(program, array, envp);
fputs("Unable to execute: ", stderr);
fputs(program, stderr);
fputs("\nPlease check file permissions and that it is a valid binary\n", stderr);
2021-11-23 00:53:12 +00:00
}
/* Prevent infinite loops */
_exit(EXIT_FAILURE);
}
/* Otherwise we are the parent */
/* And we should wait for it to complete */
waitpid(f, &status, 0);
2022-12-26 17:04:28 +00:00
result = what_exit(program, status);
#endif
if(0 != result)
2021-11-23 00:53:12 +00:00
{
fputs("Subprocess: ", stderr);
fputs(program, stderr);
fputs(" error\nAborting for safety\n", stderr);
exit(result);
2021-11-23 00:53:12 +00:00
}
}
void insert_array(char** array, int index, char* string)
{
int size = strlen(string);
array[index] = calloc(size+2, sizeof(char));
strcpy(array[index], string);
}
void spawn_hex2(char* input, char* output, char* architecture, char** envp, int debug)
2021-11-23 00:53:12 +00:00
{
2021-11-23 10:58:45 +00:00
char* elf_header = calloc(MAX_STRING, sizeof(char));
elf_header = strcat(elf_header, M2LIBC_PATH);
elf_header = strcat(elf_header, "/");
elf_header = strcat(elf_header, architecture);
elf_header = strcat(elf_header, "/ELF-");
elf_header = strcat(elf_header, architecture);
if(debug)
{
elf_header = strcat(elf_header, "-debug.hex2");
}
else
{
elf_header = strcat(elf_header, ".hex2");
}
fputs("# starting hex2 linking\n", stdout);
2021-11-23 00:53:12 +00:00
char** array = calloc(MAX_ARRAY, sizeof(char*));
insert_array(array, 0, "hex2");
insert_array(array, 1, "--file");
2021-11-23 10:58:45 +00:00
insert_array(array, 2, elf_header);
insert_array(array, 3, "--file");
insert_array(array, 4, input);
insert_array(array, 5, "--output");
insert_array(array, 6, output);
insert_array(array, 7, "--architecture");
insert_array(array, 8, architecture);
insert_array(array, 9, "--base-address");
insert_array(array, 10, BASEADDRESS);
if(ENDIAN)
{
insert_array(array, 11, "--big-endian");
}
else
{
insert_array(array, 11, "--little-endian");
}
_execute("hex2", array, envp);
2021-11-23 00:53:12 +00:00
}
void spawn_M1(char* input, char* debug_file, char* output, char* architecture, char** envp, int debug_flag)
2021-11-23 00:53:12 +00:00
{
2021-11-23 10:58:45 +00:00
fputs("# starting M1 assembly\n", stdout);
char* definitions = calloc(MAX_STRING, sizeof(char));
definitions = strcat(definitions, M2LIBC_PATH);
definitions = strcat(definitions, "/");
definitions = strcat(definitions, architecture);
definitions = strcat(definitions, "/");
definitions = strcat(definitions, architecture);
definitions = strcat(definitions, "_defs.M1");
char* libc = calloc(MAX_STRING, sizeof(char));
libc = strcat(libc, M2LIBC_PATH);
libc = strcat(libc, "/");
libc = strcat(libc, architecture);
if(STDIO_USED)
{
libc = strcat(libc, "/libc-full.M1");
}
else
{
libc = strcat(libc, "/libc-core.M1");
}
2021-11-23 00:53:12 +00:00
char** array = calloc(MAX_ARRAY, sizeof(char*));
insert_array(array, 0, "M1");
insert_array(array, 1, "--file");
2021-11-23 10:58:45 +00:00
insert_array(array, 2, definitions);
insert_array(array, 3, "--file");
insert_array(array, 4, libc);
insert_array(array, 5, "--file");
insert_array(array, 6, input);
if(ENDIAN)
{
insert_array(array, 7, "--big-endian");
}
else
{
insert_array(array, 7, "--little-endian");
}
insert_array(array, 8, "--architecture");
insert_array(array, 9, architecture);
2021-11-23 00:53:12 +00:00
if(debug_flag)
{
2021-11-23 10:58:45 +00:00
insert_array(array, 10, "--file");
insert_array(array, 11, debug_file);
insert_array(array, 12, "--output");
insert_array(array, 13, output);
2021-11-23 00:53:12 +00:00
}
else
{
2021-11-23 10:58:45 +00:00
insert_array(array, 10, "--output");
insert_array(array, 11, output);
2021-11-23 00:53:12 +00:00
}
_execute("M1", array, envp);
2021-11-23 00:53:12 +00:00
}
void spawn_blood_elf(char* input, char* output, char** envp, int large_flag)
2021-11-23 00:53:12 +00:00
{
2021-11-23 10:58:45 +00:00
fputs("# starting Blood-elf stub generation\n", stdout);
2021-11-23 00:53:12 +00:00
char** array = calloc(MAX_ARRAY, sizeof(char*));
insert_array(array, 0, "blood-elf");
insert_array(array, 1, "--file");
insert_array(array, 2, input);
2021-11-23 10:58:45 +00:00
if(ENDIAN)
{
insert_array(array, 3, "--big-endian");
}
else
{
insert_array(array, 3, "--little-endian");
}
insert_array(array, 4, "--output");
insert_array(array, 5, output);
if(large_flag) insert_array(array, 6, "--64");
_execute("blood-elf", array, envp);
2021-11-23 00:53:12 +00:00
}
void spawn_M2(char* input, char* output, char* architecture, char** envp, int debug_flag)
2021-11-23 00:53:12 +00:00
{
2021-11-23 10:58:45 +00:00
fputs("# starting M2-Planet build\n", stdout);
2021-11-23 00:53:12 +00:00
char** array = calloc(MAX_ARRAY, sizeof(char*));
insert_array(array, 0, "M2-Planet");
insert_array(array, 1, "--file");
insert_array(array, 2, input);
insert_array(array, 3, "--output");
insert_array(array, 4, output);
insert_array(array, 5, "--architecture");
insert_array(array, 6, architecture);
if(debug_flag) insert_array(array, 7, "--debug");
_execute("M2-Planet", array, envp);
2021-11-23 00:53:12 +00:00
}
void spawn_processes(int debug_flag, char* prefix, char* preprocessed_file, char* destination, char** envp)
2021-11-23 00:53:12 +00:00
{
int large_flag = FALSE;
if(WORDSIZE > 32) large_flag = TRUE;
char* M2_output = calloc(100, sizeof(char));
strcpy(M2_output, prefix);
2022-03-21 16:19:42 +00:00
strcat(M2_output, "/M2-Planet-XXXXXX");
2021-11-23 00:53:12 +00:00
int i = mkstemp(M2_output);
if(-1 != i)
{
2021-11-23 10:58:45 +00:00
close(i);
spawn_M2(preprocessed_file, M2_output, Architecture, envp, debug_flag);
2021-11-23 00:53:12 +00:00
}
else
{
fputs("unable to get a tempfile for M2-Planet output\n", stderr);
exit(EXIT_FAILURE);
}
char* blood_output = "";
if(debug_flag)
{
blood_output = calloc(100, sizeof(char));
strcpy(blood_output, prefix);
2022-03-21 16:19:42 +00:00
strcat(blood_output, "/blood-elf-XXXXXX");
2021-11-23 00:53:12 +00:00
i = mkstemp(blood_output);
if(-1 != i)
{
2021-11-23 10:58:45 +00:00
close(i);
spawn_blood_elf(M2_output, blood_output, envp, large_flag);
2021-11-23 00:53:12 +00:00
}
else
{
fputs("unable to get a tempfile for blood-elf output\n", stderr);
exit(EXIT_FAILURE);
}
}
char* M1_output = calloc(100, sizeof(char));
strcpy(M1_output, prefix);
2022-03-21 16:19:42 +00:00
strcat(M1_output, "/M1-macro-XXXXXX");
2021-11-23 00:53:12 +00:00
i = mkstemp(M1_output);
if(-1 != i)
{
2021-11-23 10:58:45 +00:00
close(i);
spawn_M1(M2_output, blood_output, M1_output, Architecture, envp, debug_flag);
2021-11-23 00:53:12 +00:00
}
else
{
fputs("unable to get a tempfile for M1 output\n", stderr);
exit(EXIT_FAILURE);
}
/* We no longer need the M2-Planet tempfile output */
2022-01-21 02:35:14 +00:00
if(!DIRTY_MODE) remove(M2_output);
2021-11-23 00:53:12 +00:00
/* Nor the blood-elf output anymore if it exists */
2022-01-21 02:35:14 +00:00
if(!match("", blood_output))
{
if(!DIRTY_MODE) remove(blood_output);
}
2021-11-23 00:53:12 +00:00
/* Build the final binary */
spawn_hex2(M1_output, destination, Architecture, envp, debug_flag);
2021-11-23 00:53:12 +00:00
/* clean up after ourselves*/
2022-01-21 02:35:14 +00:00
if(!DIRTY_MODE) remove(M1_output);
2021-11-23 00:53:12 +00:00
}