Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

UFCFWK-15-2 Resit

Operating Systems

2022-23

Section 1: Overview of Assessment

This assignment assesses the following module learning outcomes:

•    Show a detailed knowledge and understanding of the design, structure and implementation of modern operating systems (OS) as well as the data structures and interfaces of an OS (MO1)

•    Write small utility programs, in both script and compiler level languages, that interface to the system primitives (MO2)

•    Build and modify an OS, with particular application to user/system interface and memory sub-systems (MO3)

•    Understand the security problems and solutions in an OS (MO4) The assignment is worth 100% of the overall mark for the module.

The assignment is described in more detail in Section 2.

This is a group assignment.

Section 2: Assessment specifications

The assessment for this module involves developing system calls for PintOS. It consists of two sub- components, namely,

1.    Group-based system call development;

2.    Individual-based system call exploitation.

Group-based system call development

Working within assigned groups, each member must:

1.    Select a system call from the system call list in Section 6;

2.    Implement the functionality of the chosen system call on PintOS.

Please note that each member MUST choose a system call that is distinct from other team members.

In other words, each system call can be selected by no more than ONE group member. The following needs to be addressed in the selected system call development:

1.   Tokenisation of user argument input from terminal;

2.    Stack management and argument alignment;

3.   Testing and integration of developed system calls.

Individual-based system call exploitation

For this task, students must exploit their developed system call to gain kernel-level access.

To this end, students are free to use any of the memory-exploitation techniques (including but not limited to the following):

•    Buffer overflow;

•    Return-oriented programming (ROP);

•    Heap exploitation

•    Etc.

Section 3: Deliverables

The deliverables for this project will be the following:

1.   A short report covering (diagrams and screenshot where appropriate):

a.    Overall architecture of PintOS;

b.   System call design and development;

c.    Summary of system call exploitation (one per team member);

d.    Countermeasures;

e.    Gitlab link to code repository

2.   A group presentation slide which summarises the aforementioned points;

3.   Weekly Sprint project logs covering:

a.    Details of meeting (e.g., Date/Time, Location, etc);

b.    Project topics discussed;

c.    Development plans.

Section 4: Means of assessment

The means of assessment will be a in-class presentation and demonstration of project. This will take place on the week commencing 24th of July 2023.

The 20 minute presentation and demonstration session will consist of:

Group presentation discussing the PintOS architecture and details of the development

Individual presentation discussing:

o The system call selected by each student for exploitation

o Rationale(s) for choosing it (i.e., Why?)

o Details of exploitation (How, what, etc)

o Countermeasures

NB: In-class practical demonstration on the functioning of the system and exploitation required for both cases.

Section 5 Marking Criteria

NON-SUBMISSIONS are covered by UWE Regulations and generally attract zero marks The following marking criteria will be used for the assessment of your presentation

Group component of the presentation (20%)

Outstanding depth of content; Comprehensive coverage of PintOS architecture, system call development

5

4

3

2

1

0

Poor content; No questions have been addressed

Outstanding quality of presentation; appropriate use of references and citations; excellent balance between visual and textual information; appropriate language; excellent use of diagrams/tables/screenshots

5

4

3

2

1

0

Poor quality of presentation; inappropriate language; no use of screenshots/diagrams/tables; demo not provided   (either live or video)

Outstanding structure; includes introductory and presentation layout sections and clearly provides a summary and conclusions; member contribution is clearly identified on the slides; demonstrates excellent flow between the sections; sections logically organised and developed

5

4

3

2

1

0

Poor structure; no flow between the sections; member contributions not identified

The presentation is coherent, demonstrating an excellent flow.

5

4

3

2

1

0

Lacks coherence; little or no preparation

NB: Please see next page for the marking criteria for the individual component of presentation and demonstration

Individual component of the presentation (80%)

Outstanding depth of knowledge; in-depth presentation of the individual system call exploitation covered; answers demonstrate excellent understanding and insights on all aspects.

30

24

18

12

6

0

Poor depth of knowledge; answers demonstrate serious lack of understanding

Outstanding presentation skills; appropriate presentation style; use of appropriate language; looks and sounds confident in a well-balanced manner; excellent use of visual and textual information on the slides; excellent use of the slides. Well-paced and clearly audible without overreacting.

25

20

15

10

5

0

Poor presentation skills; lack of confidence. Relies heavily on the notes/slides.

Coherent presentation; well-prepared and connected

25

20

15

10

5

0

Poor preparation. Conflicts with other

Section 6 PintOS system calls

- void halt (void): Terminates Pintos by calling "shutdown_power_off" (declared in threads/init.h). This should be seldom used, because you can lose some information about the current state of the running Pintos system.

- void exit (int status): Terminates the calling user program, returning status to the kernel.  If the process' parent waits for it (see wait syscall below), the status that will be returned can be different. Conventionally, a status of 0 indicates success and nonzero values indicate errors.

- pid_t exec (const char *cmd_line): Runs the executable given in cmd_line, passing the cmd_line given arguments, and returns the new process' program ID, pid. It must return a '-1' PID, if the program cannot load or run for any reason. Thus, the parent process cannot return from the exec call until it knows  whether  the  child  process  successfully  loaded  its  executable.  You  must  use  appropriate synchronization to ensure this.

- int wait (pid_t pid): Waits for a child process defined by its pid and retrieves the child's exit status. If the PID’s process is still running, it must wait until it terminates and then, returns the status returned by the exited process defined by pid. If the process did not call "exit", but was terminated by the kernel (e.g. killed due to any exception), "wait" must return -1. It is perfectly acceptable for a parent process to wait for child processes that have already terminated by the time the parent calls “wait”, but the kernel must still allow the parent to retrieve its child exit status, or be able to know that the child was terminated by the kernel. "wait" must fail and return -1 immediately if any of the following conditions is true:

o pid does not refer to a direct child of the calling process. pid is a direct child of the calling process if and only if the calling process received pid as a return value from a successful call to exec. Note that children are not inherited: if A spawns child B and B spawns child process C, then A cannot wait for C, even if B is dead. A call to “wait(C)” by process A must fail. Similarly, orphaned processes are not assigned to a new parent if their parent process exits before they do.

o The process that calls wait has already called wait on pid. That is, a process may wait for any given child not more than once.

Processes may spawn any number of children, and wait for them in any order, they may even exit without having waited for some or all of their children. Your design should consider all the ways in which "wait" can occur. All of a process's resources, including its "thread" structure, must be freed whether its parent ever waits for it or not, and regardless of whether the child exits before or after its parent. You must also ensure that Pintos does not terminate until the initial process exits. The supplied Pintos code tries to do this by calling the "process_wait" function (in "userprog/process.c") from "main"  (in "threads/init.c").  We  suggest  that  you  implement "process_wait" according  to  the comment  at  the  top  of that  function  and  then  implement  the  wait  system  call  matching  your "process_wait" design. Implementing this system call requires considerably more work than any of the others.

- bool create (const char *file, unsigned initial_size): Creates a new file called file with a size of initial_size bytes. Returns true if successful, false otherwise. Creating a new file does not open it: opening the new file is a separate operation which requires another system call.

- bool remove (const char *file): Deletes the file named file. Returns true if successful, false otherwise. A file may be removed regardless of whether it is open or closed, also, removing an open file does not close it.

- int open (const char *file): Opens the file named file. Returns a non-negative integer handle called a "file descriptor" (fd), or -1 if the file could not be opened. File descriptors numbered 0 and 1 are reserved for the console: fd 0 (STDIN_FILENO) is the standard input, fd 1 (STDOUT_FILENO) is the standard output. The open system call will never return either of these file descriptors, which are valid as system call arguments only as explicitly described. Each process has an independent set of file descriptors. File descriptors are not inherited by child processes. When a single file is opened more than once, whether by a single process or different processes, each open returns a new file descriptor. Different file descriptors for a single file are closed independently in separate calls to “close” and they do not share a file position.

- int filesize (int fd): Returns the size, in bytes, of the file opened as fd.

- int read (int fd, void *buffer, unsigned size): Reads size bytes from the file opened as fd and place what's read into buffer. Returns the number of bytes actually read. 0 must be returned if reaching the end of a file, or -1 if the file could not be read (due to a condition other than end of file). fd 0 must allow to read from the keyboard using the “input_getc” function.

- int write (int fd, const void *buffer, unsigned size): Writes size bytes from buffer to the opened file fd. Returns the number of bytes actually written, which may be less than size if some bytes could not be written. Writing  past the end of a file would  normally extend the file,  but file growth  is  not implemented by the basic file system in Pintos. The expected behavior here is to write as many bytes as possible up to the end of a file and return the actual number written, or 0 if no bytes could be written at all. fd 1 must write to the console. To write to the console, you can write the entirety of buffer in one call to the “putbuf” function, at least as long as size is not bigger than a few