Browse Source

Reducing the number of possible segfaults through fuzzing

Jeremiah Orians 3 years ago
parent
commit
5adaf5e738
7 changed files with 189 additions and 69 deletions
  1. 27 0
      functions/file_print.c
  2. 35 0
      functions/match.c
  3. 31 0
      functions/require.c
  4. 12 12
      makefile
  5. 56 56
      vm.c
  6. 5 0
      vm.h
  7. 23 1
      vm_instructions.c

+ 27 - 0
functions/file_print.c

@@ -0,0 +1,27 @@
+/* Copyright (C) 2016 Jeremiah Orians
+ * This file is part of stage0.
+ *
+ * stage0 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.
+ *
+ * stage0 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 stage0.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include<stdio.h>
+// void fputc(char s, FILE* f);
+
+void file_print(char* s, FILE* f)
+{
+	while(0 != s[0])
+	{
+		fputc(s[0], f);
+		s = s + 1;
+	}
+}

+ 35 - 0
functions/match.c

@@ -0,0 +1,35 @@
+/* Copyright (C) 2016 Jeremiah Orians
+ * This file is part of stage0.
+ *
+ * stage0 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.
+ *
+ * stage0 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 stage0.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define FALSE 0
+// CONSTANT FALSE 0
+#define TRUE 1
+// CONSTANT TRUE 1
+
+int match(char* a, char* b)
+{
+	int i = -1;
+	do
+	{
+		i = i + 1;
+		if(a[i] != b[i])
+		{
+			return FALSE;
+		}
+	} while((0 != a[i]) && (0 !=b[i]));
+	return TRUE;
+}

+ 31 - 0
functions/require.c

@@ -0,0 +1,31 @@
+/* Copyright (C) 2016 Jeremiah Orians
+ * Copyright (C) 2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
+ * This file is part of stage0.
+ *
+ * stage0 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.
+ *
+ * stage0 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 stage0.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include<stdio.h>
+#include<stdlib.h>
+
+void file_print(char* s, FILE* f);
+
+void require(int bool, char* error)
+{
+	if(!bool)
+	{
+		file_print(error, stderr);
+		exit(EXIT_FAILURE);
+	}
+}

+ 12 - 12
makefile

@@ -25,23 +25,23 @@ production: libvm-production.so vm-production asm dis ALL-ROMS
 development: vm libvm.so asm dis ALL-ROMS
 
 # VM Builds
-vm-minimal: vm.h vm_minimal.c vm_instructions.c vm_decode.c | bin
-	$(CC) -DVM32=true vm_minimal.c vm_instructions.c vm_decode.c -o bin/vm-minimal
+vm-minimal: vm.h vm_minimal.c vm_instructions.c vm_decode.c functions/require.c functions/file_print.c functions/match.c | bin
+	$(CC) -DVM32=true vm_minimal.c vm_instructions.c vm_decode.c functions/require.c functions/file_print.c functions/match.c -o bin/vm-minimal
 
-vm16: vm.h vm.c vm_instructions.c vm_decode.c tty.c | bin
-	$(CC) -ggdb -DVM16=true -Dtty_lib=true vm.h vm.c vm_instructions.c vm_decode.c tty.c -o bin/vm16
+vm16: vm.h vm.c vm_instructions.c vm_decode.c tty.c functions/require.c functions/file_print.c functions/match.c | bin
+	$(CC) -ggdb -DVM16=true -Dtty_lib=true vm.h vm.c vm_instructions.c vm_decode.c tty.c functions/require.c functions/file_print.c functions/match.c -o bin/vm16
 
-vm: vm.h vm.c vm_instructions.c vm_decode.c tty.c | bin
-	$(CC) -ggdb -DVM32=true -Dtty_lib=true vm.c vm_instructions.c vm_decode.c tty.c -o bin/vm
+vm: vm.h vm.c vm_instructions.c vm_decode.c tty.c functions/require.c functions/file_print.c functions/match.c | bin
+	$(CC) -ggdb -DVM32=true -Dtty_lib=true vm.c vm_instructions.c vm_decode.c tty.c functions/require.c functions/file_print.c functions/match.c -o bin/vm
 
-vm64: vm.h vm.c vm_instructions.c vm_decode.c tty.c | bin
-	$(CC) -ggdb -DVM64=true -Dtty_lib=true vm.h vm.c vm_instructions.c vm_decode.c tty.c -o bin/vm64
+vm64: vm.h vm.c vm_instructions.c vm_decode.c tty.c functions/require.c functions/file_print.c functions/match.c | bin
+	$(CC) -ggdb -DVM64=true -Dtty_lib=true vm.h vm.c vm_instructions.c vm_decode.c tty.c functions/require.c functions/file_print.c functions/match.c -o bin/vm64
 
-vm-production: vm.h vm.c vm_instructions.c vm_decode.c | bin
-	$(CC) -DVM32=true vm.c vm_instructions.c vm_decode.c -o bin/vm-production
+vm-production: vm.h vm.c vm_instructions.c vm_decode.c functions/require.c functions/file_print.c functions/match.c | bin
+	$(CC) -DVM32=true vm.c vm_instructions.c vm_decode.c functions/require.c functions/file_print.c functions/match.c -o bin/vm-production
 
-vm-trace: vm.h vm.c vm_instructions.c vm_decode.c tty.c dynamic_execution_trace.c | bin
-	$(CC) -DVM32=true -ggdb -Dtty_lib=true -DTRACE=true vm.c vm_instructions.c vm_decode.c tty.c dynamic_execution_trace.c -o bin/vm
+vm-trace: vm.h vm.c vm_instructions.c vm_decode.c tty.c dynamic_execution_trace.c functions/require.c functions/file_print.c functions/match.c | bin
+	$(CC) -DVM32=true -ggdb -Dtty_lib=true -DTRACE=true vm.c vm_instructions.c vm_decode.c tty.c dynamic_execution_trace.c functions/require.c functions/file_print.c functions/match.c -o bin/vm
 
 # Build the roms
 ALL-ROMS: stage0_monitor stage1_assembler-0 SET DEHEX stage1_assembler-1 stage1_assembler-2 M0 CAT lisp cc_x86 forth

+ 56 - 56
vm.c

@@ -67,7 +67,9 @@ void execute_vm(struct lilith* vm)
 int main(int argc, char **argv)
 {
 	POSIX_MODE = false;
-	int c;
+	FUZZING = false;
+	char* c;
+	int length;
 	int Memory_Size = (16 * 1024);
 
 	tape_01_name = "tape_01";
@@ -75,70 +77,68 @@ int main(int argc, char **argv)
 	char* rom_name = NULL;
 	char class;
 
-	static struct option long_options[] = {
-		{"rom", required_argument, 0, 'r'},
-		{"tape_01", required_argument, 0, '1'},
-		{"tape_02", required_argument, 0, '2'},
-		{"memory", required_argument, 0, 'm'},
-		{"POSIX-MODE", no_argument, 0, 'P'},
-		{"help", no_argument, 0, 'h'},
-		{0, 0, 0, 0}
-	};
-	int option_index = 0;
-	while ((c = getopt_long(argc, argv, "r:h:1:2:m:P", long_options, &option_index)) != -1)
+	int i = 1;
+	while(i <= argc)
 	{
-		switch (c)
+		if(NULL == argv[i])
 		{
-			case 0: break;
-			case 'r':
-			{
-				rom_name = optarg;
-				break;
-			}
-			case 'h':
-			{
-				fprintf(stdout, "Usage: %s --rom $rom [--tape_01 $foo] [--tape_02 $bar]\n", argv[0]);
-				exit(EXIT_SUCCESS);
-			}
-			case '1':
+			i = i + 1;
+		}
+		else if(match(argv[i], "-r") || match(argv[i], "--rom"))
+		{
+			rom_name = argv[i + 1];
+			i = i + 2;
+		}
+		else if(match(argv[i], "-h") || match(argv[i], "--help"))
+		{
+			fprintf(stdout, "Usage: %s --rom $rom [--tape_01 $foo] [--tape_02 $bar]\n", argv[0]);
+			exit(EXIT_SUCCESS);
+		}
+		else if(match(argv[i], "-1") || match(argv[i], "--tape_01"))
+		{
+			tape_01_name = argv[i + 1];
+			i = i + 2;
+		}
+		else if(match(argv[i], "-2") || match(argv[i], "--tape_02"))
+		{
+			tape_02_name = argv[i + 1];
+			i = i + 2;
+		}
+		else if(match(argv[i], "-m") || match(argv[i], "--memory"))
+		{
+			length = strlen(argv[i + 1]) - 1;
+			c = argv[i+1];
+			class = c[length];
+			c[length] = 0;
+			Memory_Size = atoi(c);
+			if('K' == class)
 			{
-				tape_01_name = optarg;
-				break;
+				Memory_Size = Memory_Size * 1024;
 			}
-			case '2':
+			else if('M' == class)
 			{
-				tape_02_name = optarg;
-				break;
+				Memory_Size = Memory_Size * 1024 * 1024;
 			}
-			case 'm':
+			else if('G' == class)
 			{
-				int length = strlen(optarg) - 1;
-				class = optarg[length];
-				optarg[length] = 0;
-				Memory_Size = atoi(optarg);
-				if('K' == class)
-				{
-					Memory_Size = Memory_Size * 1024;
-				}
-				else if('M' == class)
-				{
-					Memory_Size = Memory_Size * 1024 * 1024;
-				}
-				else if('G' == class)
-				{
-					Memory_Size = Memory_Size * 1024 * 1024 * 1024;
-				}
-				break;
+				Memory_Size = Memory_Size * 1024 * 1024 * 1024;
 			}
-			case 'P':
-			{
+			i = i + 2;
+		}
+		else if(match(argv[i], "-P") || match(argv[i], "--POSIX-MODE"))
+		{
 				POSIX_MODE = true;
-				break;
-			}
-			default:
-			{
-				exit(EXIT_FAILURE);
-			}
+				i = i + 1;
+		}
+		else if(match(argv[i], "-F") || match(argv[i], "--fuzzing"))
+		{
+			FUZZING = true;
+			i = i + 1;
+		}
+		else
+		{
+			fprintf(stderr, "unknown option %s\n", argv[i]);
+			exit(EXIT_FAILURE);
 		}
 	}
 

+ 5 - 0
vm.h

@@ -322,3 +322,8 @@ char* tape_02_name;
 
 /* Enable POSIX Mode */
 bool POSIX_MODE;
+bool FUZZING;
+
+/* Commonly useful functions */
+void require(int boolean, char* error);
+int match(char* a, char* b);

+ 23 - 1
vm_instructions.c

@@ -255,7 +255,11 @@ void vm_FOPEN_READ(struct lilith* vm)
 
 void vm_FOPEN_WRITE(struct lilith* vm)
 {
-	if(POSIX_MODE)
+	if(FUZZING)
+	{
+		vm->reg[0] = 0;
+	}
+	else if(POSIX_MODE)
 	{
 		char* s = string_copy(vm, vm->reg[0]);
 		/* 577 is O_WRONLY|O_CREAT|O_TRUNC, 384 is 600 in octal */
@@ -286,12 +290,16 @@ void vm_FCLOSE(struct lilith* vm)
 	{
 		if(0x00001100 == vm->reg[0])
 		{
+			require(NULL != tape_01, "tape_01 not valid for fclose\nAborting to prevent issues\n");
 			fclose(tape_01);
+			tape_01 = NULL;
 		}
 
 		if (0x00001101 == vm->reg[0])
 		{
+			require(NULL != tape_02, "tape_02 not valid for fclose\nAborting to prevent issues\n");
 			fclose(tape_02);
+			tape_02 = NULL;
 		}
 	}
 }
@@ -306,11 +314,13 @@ void vm_FSEEK(struct lilith* vm)
 	{
 		if(0x00001100 == vm->reg[0])
 		{
+			require(NULL != tape_01, "tape_01 not valid for fseek\nAborting to prevent issues\n");
 			fseek(tape_01, vm->reg[1], SEEK_CUR);
 		}
 
 		if (0x00001101 == vm->reg[0])
 		{
+			require(NULL != tape_02, "tape_02 not valid for fseek\nAborting to prevent issues\n");
 			fseek(tape_02, vm->reg[1], SEEK_CUR);
 		}
 	}
@@ -326,11 +336,13 @@ void vm_REWIND(struct lilith* vm)
 	{
 		if(0x00001100 == vm->reg[0])
 		{
+			require(NULL != tape_01, "tape_01 not valid for rewind\nAborting to prevent issues\n");
 			rewind(tape_01);
 		}
 
 		if (0x00001101 == vm->reg[0])
 		{
+			require(NULL != tape_02, "tape_02 not valid for rewind\nAborting to prevent issues\n");
 			rewind(tape_02);
 		}
 	}
@@ -359,11 +371,13 @@ void vm_FGETC(struct lilith* vm)
 
 		if(0x00001100 == vm->reg[1])
 		{
+			require(NULL != tape_01, "tape_01 not valid for fgetc\nAborting to prevent issues\n");
 			byte = fgetc(tape_01);
 		}
 
 		if (0x00001101 == vm->reg[1])
 		{
+			require(NULL != tape_02, "tape_02 not valid for fgetc\nAborting to prevent issues\n");
 			byte = fgetc(tape_02);
 		}
 	}
@@ -391,11 +405,13 @@ void vm_FPUTC(struct lilith* vm)
 
 		if(0x00001100 == vm->reg[1])
 		{
+			require(NULL != tape_01, "tape_01 not valid for fputc\nAborting to prevent issues\n");
 			fputc(byte, tape_01);
 		}
 
 		if (0x00001101 == vm->reg[1])
 		{
+			require(NULL != tape_02, "tape_02 not valid for fputc\nAborting to prevent issues\n");
 			fputc(byte, tape_02);
 		}
 	}
@@ -793,6 +809,7 @@ void DIVIDE(struct lilith* vm, struct Instruction* c)
 
 	tmp1 = (signed_vm_register)(vm->reg[c->reg2]);
 	tmp2 = (signed_vm_register)(vm->reg[c->reg3]);
+	require(0 != tmp2, "DIVIDE by zero exception\n");
 	vm->reg[c->reg0] = tmp1 / tmp2;
 	vm->reg[c->reg1] = tmp1 % tmp2;
 }
@@ -803,6 +820,7 @@ void DIVIDEU(struct lilith* vm, struct Instruction* c)
 
 	utmp1 = vm->reg[c->reg2];
 	utmp2 = vm->reg[c->reg3];
+	require(0 != utmp2, "DIVIDEU by zero exception\n");
 	vm->reg[c->reg0] = utmp1 / utmp2;
 	vm->reg[c->reg1] = utmp1 % utmp2;
 }
@@ -1026,6 +1044,7 @@ void DIV(struct lilith* vm, struct Instruction* c)
 	tmp1 = (signed_vm_register)(vm->reg[c->reg1]);
 	tmp2 = (signed_vm_register)(vm->reg[c->reg2]);
 
+	require(0 != tmp2, "DIV by zero exception\n");
 	vm->reg[c->reg0] = tmp1 / tmp2;
 }
 
@@ -1036,16 +1055,19 @@ void MOD(struct lilith* vm, struct Instruction* c)
 	tmp1 = (signed_vm_register)(vm->reg[c->reg1]);
 	tmp2 = (signed_vm_register)(vm->reg[c->reg2]);
 
+	require(0 != tmp2, "MOD by zero exception\n");
 	vm->reg[c->reg0] = tmp1 % tmp2;
 }
 
 void DIVU(struct lilith* vm, struct Instruction* c)
 {
+	require(0 != vm->reg[c->reg2], "DIVU by zero exception\n");
 	vm->reg[c->reg0] = vm->reg[c->reg1] / vm->reg[c->reg2];
 }
 
 void MODU(struct lilith* vm, struct Instruction* c)
 {
+	require(0 != vm->reg[c->reg2], "MODU by zero exception\n");
 	vm->reg[c->reg0] = vm->reg[c->reg1] % vm->reg[c->reg2];
 }