Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • y2-rhymansaib/pintos_student
1 result
Select Git revision
Show changes
Commits on Source (21)
......@@ -40,7 +40,7 @@ endif
# Compiler and assembler invocation.
DEFINES =
WARNINGS = -Wall -W -Wstrict-prototypes -Wmissing-prototypes -Wsystem-headers
CFLAGS = -g -msoft-float -O -DBEN_MODS -std=gnu99
CFLAGS = -g -msoft-float -O0 -DBEN_MODS -std=gnu99
CPPFLAGS = -nostdinc -I$(SRCDIR) -I$(SRCDIR)/lib
ASFLAGS = -Wa,--gstabs
LDFLAGS =
......
......@@ -4,7 +4,7 @@ SRCDIR = ..
# To add a new test, put its name on the PROGS list
# and then add a name_SRC line that lists its source files.
PROGS = cat cmp cp echo halt hex-dump ls mcat mcp mkdir pwd rm shell \
bubsort insult lineup matmult recursor my
bubsort insult lineup matmult recursor my crack shellcode
# Should work from project 2 onward.
cat_SRC = cat.c
......@@ -19,6 +19,8 @@ ls_SRC = ls.c
recursor_SRC = recursor.c
rm_SRC = rm.c
my_SRC = my.c
crack_SRC = crack.c
shellcode_SRC = shellcode.c
# Should work in project 3; also in project 4 if VM is included.
bubsort_SRC = bubsort.c
......
#include <stdio.h>
#include <syscall.h>
#include <syscall.c>
int
main (int argc, char **argv)
{
printf ("Executing Crack !!! \n");
}
\ No newline at end of file
/* klaar@ida
pintos -v --fs-disk=2 -p ../examples/crack -a crack -p ../examples/shellcode -a shellcode -- -f -q run 'shellcode'
-*- Woahhh, have fun -*-
http://www.phrack.org/issues.html?issue=49&id=14#article
http://www.phrack.org/issues.html?issue=57&id=15#article
Somewhat simpler to achieve in Pintos actually.
*/
#include <syscall.h>
char shellcode[] =
"\xE9\x0A\x00\x00\x00\x6A\x02\xCD\x30\x6A\x00\x6A\x01\xCD\x30\xE8\xF1\xFF\xFF\xFF""crack";
int main( void )
{
#if 1
int *ret; /* A local variable is stored on the stack. */
ret = (int *)&ret + 2; /* Two steps above in the stack is the
* address to continue at when main
* return... the normal function return
* address. */
(*ret) = (int)shellcode; /* We overwrite it with the address to the
* shell code. This will check that the
* shell code works as expected. */
return 0;
#else
/* Assembler code to do the following:
*
* exec("crack");
* exit();
*
* Apparently the code 0x01 can not be sent as input to pintos, so
* it can not be part of any instruction. Reason unknown. Theory:
* 0x01 may be grabbed as Ctrl-a by QEMU ?
*
* Translate push 0x01 ==> ... push %eax
*
* The tricky part is to figure out at which address the name of the
* program to start is stored. The call instruction solves it
* nicely. It saves the following address as return address.
*/
__asm__("jmp 0x0f;" /* jump to CALL */
/* actual address of string pushed as return address by CALL */
"push $0x2;" /* push EXEC syscall number */
"int $0x30;" /* make syscall */
"push %0x0;" /* push exit_status (eax = 0)*/
"push %0x1;" /* push EXIT syscall number(eax = 1) */
"int $0x30;" /* make syscall */
/* CALL */"call -0x0C;" /* jumps back again */
".string \"crack\";" /* program to start */
);
#endif
}
......@@ -59,7 +59,8 @@ static unsigned thread_ticks; /* # of timer ticks since last yield. */
If true, use multi-level feedback queue scheduler.
Controlled by kernel command-line option "-o mlfqs". */
bool thread_mlfqs;
/* file descriptor lock */
struct lock file_lock;
static void kernel_thread (thread_func *, void *aux);
static void idle (void *aux UNUSED);
......@@ -179,6 +180,7 @@ thread_create (const char *name, int priority,
struct switch_entry_frame *ef;
struct switch_threads_frame *sf;
tid_t tid;
enum intr_level old_level;
ASSERT (function != NULL);
......@@ -191,6 +193,11 @@ thread_create (const char *name, int priority,
init_thread (t, name, priority);
tid = t->tid = allocate_tid ();
/* Prepare thread for first run by initializing its stack.
Do this atomically so intermediate values for the 'stack'
member cannot be observed. */
old_level = intr_disable ();
/* Stack frame for kernel_thread(). */
kf = alloc_frame (t, sizeof *kf);
kf->eip = NULL;
......@@ -206,6 +213,21 @@ thread_create (const char *name, int priority,
sf->eip = switch_entry;
sf->ebp = 0;
intr_set_level (old_level);
/* Set Value */
t->next_fd = 2;
t->file_descriptor = palloc_get_page(0);
if(t->file_descriptor == NULL)
return TID_ERROR;
t->childelem.next = NULL;
t->childelem.prev = NULL;
t->parent_thread = thread_current();
t->load_success = false;
t->process_exit = false;
sema_init(&(t->load_semaphore),0);
sema_init(&(t->exit_semaphore),0);
list_push_back(&(thread_current()->child_list),&(t->childelem));
/* Add to run queue. */
thread_unblock (t);
......@@ -299,6 +321,10 @@ thread_exit (void)
when it calls thread_schedule_tail(). */
intr_disable ();
list_remove (&thread_current()->allelem);
thread_current()->process_exit = true;
if(thread_current() != initial_thread){
sema_up(&(thread_current()->exit_semaphore));
}
thread_current ()->status = THREAD_DYING;
schedule ();
NOT_REACHED ();
......@@ -474,9 +500,11 @@ init_thread (struct thread *t, const char *name, int priority)
//t->is_kernel = is_kernel;
old_level = intr_disable ();
//old_level = intr_disable ();
list_push_back (&all_list, &t->allelem);
intr_set_level (old_level);
//intr_set_level (old_level);
/* child process list init*/
list_init(&(t->child_list));
}
......
......@@ -4,6 +4,8 @@
#include <debug.h>
#include <list.h>
#include <stdint.h>
#include "threads/synch.h"
#include "lib/kernel/list.h"
/* States in a thread's life cycle. */
enum thread_status
......@@ -83,6 +85,7 @@ typedef int tid_t;
struct thread
{
/* Owned by thread.c. */
struct list_elem childelem; /* List element for child_list */
tid_t tid; /* Thread identifier. */
enum thread_status status; /* Thread state. */
char name[16]; /* Name (for debugging purposes). */
......@@ -96,10 +99,24 @@ struct thread
#ifdef USERPROG
/* Owned by userprog/process.c. */
uint32_t *pagedir; /* Page directory. */
uint8_t *current_esp; /* The current value of the user program’s stack pointer.
A page fault might occur in the kernel, so we might
need to store esp on transition to kernel mode*/
#endif
/* Owned by thread.c. */
unsigned magic; /* Detects stack overflow. */
/* VALUE */
struct file **file_descriptor;
int next_fd;
bool load_success;
bool process_exit;
int process_exit_status;
struct semaphore load_semaphore;
struct semaphore exit_semaphore;
struct thread *parent_thread;
struct list child_list;
};
/* If false (default), use round-robin scheduler.
......
......@@ -21,6 +21,9 @@
static thread_func start_process NO_RETURN;
static bool load(const char *cmdline, void (**eip)(void), void **esp);
#define WORD_SIZE 4
/* Starts a new thread running a user program loaded from
FILENAME. The new thread may be scheduled (and may even exit)
before process_execute() returns. Returns the new process's
......@@ -28,24 +31,105 @@ static bool load (const char *cmdline, void (**eip) (void), void **esp);
tid_t
process_execute(const char *file_name)
{
char *fn_copy;
char *file_copy;
tid_t tid;
char *ptr = NULL;
int file_name_length = strlen(file_name) + 1;
char program[file_name_length];
/* Make a copy of FILE_NAME.
Otherwise there's a race between the caller and load(). */
fn_copy = palloc_get_page (0);
if (fn_copy == NULL)
/* Make a copy of command line. Otherwise there's a race between the caller and load(). */
file_copy = palloc_get_page(0);
if (file_copy == NULL)
return TID_ERROR;
strlcpy (fn_copy, file_name, PGSIZE);
strlcpy(file_copy, file_name, PGSIZE);
/* Parse first argument as program name */
strlcpy(program, file_name, file_name_length);
strtok_r(program, " ", &ptr);
printf("Program name: %s\n", program) ;
/* Create a new thread to execute FILE_NAME. */
tid = thread_create (file_name, PRI_DEFAULT, start_process, fn_copy);
tid = thread_create(file_name, PRI_DEFAULT, start_process, file_copy);
if (tid == TID_ERROR)
palloc_free_page (fn_copy);
{
palloc_free_page(file_copy);
}
return tid;
}
/* add file to file descriptor */
int process_add_file(struct file *f)
{
struct file **fd = NULL;
int nextFd;
fd = thread_current()->file_descriptor;
nextFd = thread_current()->next_fd;
if(fd != NULL)
{
fd[nextFd] = f;
thread_current()->next_fd = thread_current()->next_fd+1;
return nextFd;
}
else
{
return -1;
}
}
/* get struct file */
struct file *process_get_file(int fd)
{
struct file *pReturn;
if(fd < thread_current()->next_fd)
{
pReturn = thread_current()->file_descriptor[fd];
return pReturn;
}
else
{
return NULL;
}
}
/* close file function */
void
process_close_file(int fd)
{
struct file *delete_file;
delete_file = process_get_file(fd);
if(delete_file != NULL)
{
file_close(delete_file);
thread_current()->file_descriptor[fd] = NULL;
}
}
/* get_child_process */
struct thread *get_child_process(int pid)
{
struct list *child_list=&(thread_current()->child_list);
struct thread *child_process = NULL;
struct list_elem *element;
/* find child process and return */
for(element=list_begin(child_list); element != list_end(child_list); element=list_next(element))
{
child_process = list_entry(element,struct thread,childelem);
if(child_process->tid == pid)
return child_process;
}
return NULL;
}
/* remove_child_process */
void
remove_child_process(struct thread *cp)
{
if(cp != NULL)
{
list_remove(&(cp->childelem));
palloc_free_page(cp);
}
}
/* References: G,Ko(2015), pintos. Available from: https://github.com/GunjuKo/pintos [accessed on 20/11/22]*/
/* A thread function that loads a user process and starts it
running. */
static void
......@@ -54,6 +138,19 @@ start_process (void *file_name_)
char *file_name = file_name_;
struct intr_frame if_;
bool success;
char *parse[255];
char *token;
char *ptr;
int count = 0;
for (token = strtok_r(file_name, " ", &ptr); token != NULL;
token = strtok_r(NULL, " ", &ptr))
{
parse[count] = token;
count++;
printf("Tokenized Argument: %s\n", parse[count - 1]);
}
printf("Number of tokenized Arguments : %d\n", count);
/* Initialize interrupt frame and load executable. */
memset(&if_, 0, sizeof if_);
......@@ -61,7 +158,16 @@ start_process (void *file_name_)
if_.cs = SEL_UCSEG;
if_.eflags = FLAG_IF | FLAG_MBS;
success = load (file_name, &if_.eip, &if_.esp);
success = load(parse[0], &if_.eip, &if_.esp);
/* load finished sema up */
thread_current()->load_success=success;
/* push arguments */
argument_pushing(&parse, count, &if_.esp);
sema_up(&(thread_current()->load_semaphore));
//hex_dump(if_.esp, if_.esp, PHYS_BASE - if_.esp, true);
/* If load failed, quit. */
palloc_free_page(file_name);
......@@ -136,7 +242,7 @@ process_activate (void)
interrupts. */
tss_update();
}
/* We load ELF binaries. The following definitions are taken
from the ELF specification, [ELF1], more-or-less verbatim. */
......@@ -236,13 +342,7 @@ load (const char *file_name, void (**eip) (void), void **esp)
}
/* Read and verify executable header. */
if (file_read (file, &ehdr, sizeof ehdr) != sizeof ehdr
|| memcmp (ehdr.e_ident, "\177ELF\1\1\1", 7)
|| ehdr.e_type != 2
|| ehdr.e_machine != 3
|| ehdr.e_version != 1
|| ehdr.e_phentsize != sizeof (struct Elf32_Phdr)
|| ehdr.e_phnum > 1024)
if (file_read(file, &ehdr, sizeof ehdr) != sizeof ehdr || memcmp(ehdr.e_ident, "\177ELF\1\1\1", 7) || ehdr.e_type != 2 || ehdr.e_machine != 3 || ehdr.e_version != 1 || ehdr.e_phentsize != sizeof(struct Elf32_Phdr) || ehdr.e_phnum > 1024)
{
printf("load: %s: error loading executable\n", file_name);
goto done;
......@@ -287,8 +387,7 @@ load (const char *file_name, void (**eip) (void), void **esp)
/* Normal segment.
Read initial part from disk and zero the rest. */
read_bytes = page_offset + phdr.p_filesz;
zero_bytes = (ROUND_UP (page_offset + phdr.p_memsz, PGSIZE)
- read_bytes);
zero_bytes = (ROUND_UP(page_offset + phdr.p_memsz, PGSIZE) - read_bytes);
}
else
{
......@@ -321,7 +420,7 @@ load (const char *file_name, void (**eip) (void), void **esp)
file_close(file);
return success;
}
/* load() helpers. */
static bool install_page(void *upage, void *kpage, bool writable);
......@@ -429,6 +528,61 @@ load_segment (struct file *file, off_t ofs, uint8_t *upage,
}
return true;
}
/* References: J,Choi(2014), pintos. Available from: https://github.com/wookayin/pintos [accessed on 23/11/22]*/
void
argument_pushing(char **parse, int count, void **esp)
{
int i, j;
int length = 0; // Argument length
int parse0_address; // First Argument's Adress
int address[count]; // Argument adress
if(parse==NULL)
return;
/*Push arguments to stack one by one*/
for (i = count - 1; i > -1; i--)
{
for (j = strlen(parse[i]); j > -1; j--)
{
*esp = *esp - 1;
**(char **)esp = parse[i][j];
length++; /*Count length of arguments we pushed*/
}
/*Store address of argument*/
address[i] = *(unsigned int *)esp;
}
/* Word Allignment*/
for (i = 0; i < 4 - (length % 4); i++)
{
*esp = *esp - 1;
**(uint8_t **)esp = 0;
}
/* Last argument needs to be NULL*/
*esp=*esp-4;
**(char* **)esp = 0;
/*Push argument adress - Use counter to set **esp */
for (i = count - 1; i >= 0; i--)
{
*esp=*esp-4;
**(char* **)esp = (char *)address[i];
}
/* Set **argv - Main argv*/
parse0_address = *(unsigned int *)esp;
*esp=*esp-4;
**(char* **)esp = (char *)parse0_address;
/* Set counter - Main argc*/
*esp=*esp-4;
**(int **)esp=count;
/*Fake Adress - Set ret*/
*esp=*esp-4;
**(int **)esp=0;
}
/* Create a minimal stack by mapping a zeroed page at the top of
user virtual memory. */
......@@ -442,9 +596,9 @@ setup_stack (void **esp)
if (kpage != NULL)
{
success = install_page(((uint8_t *)PHYS_BASE) - PGSIZE, kpage, true);
if (success) {
if (success)
*esp = PHYS_BASE;
} else
else
palloc_free_page(kpage);
}
return success;
......@@ -466,8 +620,8 @@ install_page (void *upage, void *kpage, bool writable)
/* Verify that there's not already a page at that virtual
address, then map our page there. */
return (pagedir_get_page (t->pagedir, upage) == NULL
&& pagedir_set_page (t->pagedir, upage, kpage, writable));
return (pagedir_get_page(t->pagedir, upage) == NULL && pagedir_set_page(t->pagedir, upage, kpage, writable));
}
//--------------------------------------------------------------------
......@@ -3,9 +3,20 @@
#include "threads/thread.h"
void argument_pushing(char **parse, int count, void **esp);
struct thread *get_child_process(int pid);
void remove_child_process(struct thread *cp);
int process_add_file(struct file *f);
struct file *process_get_file(int fd);
void process_close_file(int fd);
void process_exit(void);
tid_t process_execute (const char *file_name);
int process_wait (tid_t);
void process_exit (void);
void process_activate (void);
#endif /* userprog/process.h */
#include "userprog/syscall.h"
#include <stdbool.h>
#include <stdio.h>
#include <syscall-nr.h>
#include "threads/interrupt.h"
#include "threads/thread.h"
#include "threads/vaddr.h"
#include <devices/shutdown.h>
#include <filesys/filesys.h>
#include <filesys/file.h>
#include <userprog/process.h>
#include <devices/input.h>
static void syscall_handler (struct intr_frame *);
/*System call initializer*/
void
syscall_init (void)
{
intr_register_int (0x30, 3, INTR_ON, syscall_handler, "syscall");
}
/*Handler for system commands.*/
static void
syscall_handler (struct intr_frame *f UNUSED)
{
printf ("system call!\n");
int syscall_number;
int argument[5];
void *esp = f->esp;
check_address(esp);
syscall_number = *(int *)esp;
switch (syscall_number) {
case SYS_HALT: // 0
/*Terminate PintOS*/
syscall_halt();
break;
case SYS_EXIT: //1
get_argument(esp,argument,1);
syscall_exit(argument[0]);
break;
case SYS_EXEC: // 2
get_argument(esp,argument,1);
check_address((void *)argument[0]);
f->eax = syscall_exec((const char *)argument[0]);
break;
case SYS_CREATE: // 4
get_argument(esp,argument,2);
check_address((void *)argument[0]);
f->eax = syscall_create((const char *)argument[0],(unsigned)argument[1]);
break;
case SYS_REMOVE: // 5
get_argument(esp,argument,1);
check_address((void *)argument[0]);
f->eax=syscall_remove((const char *)argument[0]);
break;
case SYS_WRITE: //9
get_argument(esp,argument,3);
check_address((void *)argument[1]);
f->eax = syscall_write(argument[0],(void *)argument[1],(unsigned)argument[2]);
break;
/* Unimplemented system calls */
default:
printf("ERROR: system call ( %d ) has not implemented!\n", syscall_number);
/* Terminate. */
syscall_exit(-1);
break;
}
}
/********SYSTEMCALLS********/
/* Halt */
void syscall_halt(void) {
shutdown_power_off(); /* From shutdown.h */
}
/* Exit */
void syscall_exit(int status) {
struct thread *current_process=thread_current();
current_process->process_exit_status = status;
printf("%s: exit(%d)\n",current_process->name,status);
thread_exit();
}
/* Execute */
/* create child process and wait until childprocess is loaded */
/* runs the executable whose name is given */
tid_t
syscall_exec(const char *argument)
{
printf("System executing %s ...\n", argument);
/*dynamically create struct child*/
struct thread *child_process;
/*new process'c program id*/
tid_t pid;
pid = process_execute(argument);
/* the child calls sema_up after the done in load()*/
child_process = get_child_process(pid);
/*Call sema_down before we return, so parent process cannot return from the exec call
until it knows that the child process has loaded or not.
Only the parent process proceed past the sema_down line and return.*/
sema_down(&(child_process->load_semaphore));
if(child_process->load_success==true)
return pid;
else
{
return -1;
}
}
/* Create File */
bool syscall_create(const char* file_name, unsigned initial_size) {
bool if_created = false;
if( filesys_create(file_name, initial_size)==true){
if_created = true;
}
return if_created;
}
/* Remove File */
bool syscall_remove(const char* file_name) {
bool if_removed = false;
if( filesys_remove(file_name)==true){
if_removed = true;
}
return if_removed;
}
/* write file */
int syscall_write(int fd, void *buffer, unsigned size)
{
int write_size = 0;
struct file *current_file;
if(fd == 1) /*stdout */
{
putbuf((const char *)buffer,size);
write_size = size;
}
else
{
current_file = process_get_file(fd);
if(current_file != NULL)
write_size = file_write(current_file,(const void *)buffer,size);
}
return write_size;
}
/* References: G,Ko(2015), pintos. Available from: https://github.com/GunjuKo/pintos [accessed on 30/11/22]*/
/****OTHER FUNCTIONS****/
void
check_address(void *addr)
{
uint32_t address=(unsigned int)addr;
uint32_t lowest=0x8048000;
uint32_t highest=0xc0000000;
if(address >= lowest && address < highest){
return;
}
else{
syscall_exit(-1);
}
}
/* References: G,Ko(2015), pintos. Available from: https://github.com/GunjuKo/pintos [accessed on 30/11/22]*/
/* get_argument function */
void
get_argument(void *esp, int *argument, int count)
{
int i;
void *stack_ptr=esp+4;
if(count > 0)
{
for(i=0; i<count; i++){
check_address(stack_ptr);
argument[i] = *(int *)stack_ptr;
stack_ptr = stack_ptr + 4;
}
}
}
\ No newline at end of file
#ifndef USERPROG_SYSCALL_H
#define USERPROG_SYSCALL_H
#include "threads/thread.h"
#include <stdbool.h>
#include <stddef.h>
void syscall_init (void);
void check_address(void *addr);
void get_argument(void *esp, int *argument, int count);
void syscall_halt(void);
void syscall_exit(int status);
tid_t
syscall_exec(const char *command);
bool syscall_create(const char* file_name, unsigned initial_size);
bool syscall_remove(const char* file_name);
int syscall_write(int fd, void *buffer, unsigned size);
#endif /* userprog/syscall.h */