<- previous index next ->
The Intel 80x86 and beyond have privilege levels. There are instructions that can only be executed at the highest privilege level, CPL = 0. This would be reserved for the operating system in order to prevent the average user from causing chaos. e.g. The average user could issue a HLT instruction to halt the machine and thus every process would be dead. Other CPL=0 only instructions include: CLTS Clear Task Switching flag in cr0 INVP Invalidate cache INVLPG Invalidate translation lookaside buffer, TLB WBINVD Write Back and Invalidate cache It should be obvious that when running a multiprocessing operating system, that there are many instructions that only the operating system should use. The operating system controls the resources of the computer, including RAM, I/O and user processes. Some sample protections are tested by the following sample programs: A few simple tests to be sure protections are working. These three programs result in segfault, intentionally. safe_64.asm store into read only section ; safe_64.asm for testing protections within sections ; Assemble: nasm -f elf64 safe_64.asm ; Link: gcc -o safe_64 safe_64.o ; Run: ./safe_64 ; Output: ; it should stop with a system caught error global main ; the standard gcc entry point extern printf ; the C function, to be called section .rodata ; read only data section, constants a: dq 5 ; long int a=5; fmt: db "Bad, still running",10,0 section .text ; Code section. not writeable main: ; the program label for the entry point push rbp ; set up stack frame mov rax,0x789abcde mov [a],rax ; should be error, read only section !!!!!!!!!! mov rdi,fmt ; address of format string mov rax,0 call printf pop rbp mov rax,0 ; normal, no error, return value ret ; return safe1_64.asm store into code section ; safe_64.asm for testing protections within sections ; Assemble: nasm -f elf64 safe1_64.asm ; Link: gcc -o safe1_64 safe1_64.o ; Run: ./safe1_64 ; Output: ; it should stop with a system caught error global main ; the standard gcc entry point extern printf ; the C function, to be called section .rodata ; read only data section, constants a: dq 5 ; long int a=5; fmt: db "Bad, still running",10,0 section .text ; Code section. not writeable main: ; the program label for the entry point push rbp ; set up stack frame mov rax,0x789abcde mov [main],rax ; should be error, can not change code .text !!!!!! mov rdi,fmt ; address of format string mov rax,0 call printf pop rbp mov rax,0 ; normal, no error, return value ret ; return safe2_64.asm jump (execute) data ; safe2_64.asm for testing protections within sections ; Assemble: nasm -f elf64 safe2_64.asm ; Link: gcc -o safe2_64 safe2_64.o ; Run: ./safe2_64 ; Output: ; it should stop with a system caught error global main ; the standard gcc entry point extern printf ; the C function, to be called section .rodata ; read only data section, constants a: dq 5 ; long int a=5; fmt: db "Bad, still running",10,0 section .text ; Code section. not writeable main: ; the program label for the entry point push rbp ; set up stack frame mov rax,0x789abcde jmp a ; should be error, can not execute data !!!!!!!! mov rdi,fmt ; address of format string mov rax,0 call printf pop rbp mov rax,0 ; normal, no error, return value ret ; return A few simple tests to be sure privileged instructions can not execute. priv_64.asm hlt instruction to halt computer ; priv_64.asm for testing that average user ; can not execute privileged instructions ; Assemble: nasm -f elf64 priv_64.asm ; Link: gcc -o priv_64 priv_64.o ; Run: ./priv_64 ; Output: ; it should stop with a system caught error global main ; the standard gcc entry point extern printf ; the C function, to be called fmt: db "bad! Still running",10,0 ; The printf format, "\n",'0' section .text ; try to halt the computer main: ; the program label for the entry point push rbp ; set up stack frame hlt ; should be error, only allowed in CPL=0 !!!!!!! mov rdi,fmt ; address of format string mov rax,0 call printf pop rbp mov rax,0 ; normal, no error, return value ret ; return priv1_64.asm other privileged instructions ; priv1_64.asm for testing that average user ; can not execute privileged instructions ; Assemble: nasm -f elf64 priv1_64.asm ; Link: gcc -o priv1_64 priv1_64.o ; Run: ./priv1_64 ; Output: ; it should stop with a system caught error global main ; the standard gcc entry point extern printf ; the C function, to be called fmt: db "bad! Still running",10,0 ; The printf format, "\n",'0' section .text ; try to halt the computer main: ; the program label for the entry point push rbp ; set up stack frame clts ; should be error, only allowed in CPL=0 !!!!!!! wbinvd ; never gets to these, also error mov rdi,fmt ; address of format string mov rax,0 call printf pop rbp mov rax,0 ; normal, no error, return value ret ; return In order to allow the user some access, controlled access, to system resources, an interface to the operating system, or kernel, is provided. You will see in the next lecture that some BIOS functions are also provided as Linux kernel calls. To implement list in NASMlist_64.c Here is some sample code related to first "push" ; test_alist_64.asm generating test data in heap and list ; (some list_64.c included as comments) extern printf ; static char heap[20000] ; space to store strings, do not reuse or free ; static char *hp = heap; ; pointer to next available heap space ; static long int list[1000]; ; space to store list block (2 index+ pointer) ; static long int lp=1; ; index to next available list space ; static char *q; ; q, a pointer to a character ; static long int i; ; a variable index section .bss heap: resb 20000 ; could be gigabytes list: resq 1000 ; could be millions q: resq 1 ; may be just in rsi i: resq 1 ; may be just in rdi section .data hp: dq heap ; [hp] is pointer to next free heap lp: dq 1 ; index of next available list item test: db "middle",0, "last",0, "front",0 ; just using middle fmt1: db "%s",10,0 ; "%s\n" for printf fmtend: db 10,0 ; "\n" ; push_back "middle", push_back "last", push_front "front" ; +-----------------+ +-----------------+ +-----------------+ ; L[0]-> | index to next----->| index to next----->| 0 | ; | 0 |<-----index to prev |<-----index to prev |<-L[1] ; | ptr to heap str | | ptr to heap str | | ptr to heap str | ; +-----------------+ +-----------------+ +-----------------+ ; The pointers to heap strings are character pointers to terminated strings. ; The "index" values could be pointers rather than indices. global main main: push rbp ; save rbp, no registers need saving ;set up test for the first push into the list mov rax,1 ; initial list index (*8 for address) mov qword [list+8*rax],0 ; list[1]=0 no more mov qword [list+8*(rax+1)],0 ; list[2]=0 no more mov rbx,[hp] ; string address in heap mov [list+8*(rax+2)],rbx ; list[3] = string address in heap ; set L[0] = 1 = rax this is first push ; set L[1] = 1 = rax mov rbx, 0 ; clear rbx, we use bl for byte mov rsi, test ; similar to a push_front call mov rax, [hp] ; address of heap in rax move: mov bl, [rsi] ; picks up a character from test mov [rax], bl ; put character on heap inc rsi ; increment from address, user inc rax ; increment to address, heap cmp bl, 0 jne move mov [hp],rax ; next available heap address saved mov rdi, fmt1 mov rsi, heap mov rax, 0 call printf pop rbp mov rax, 0 ret ; return Questions? Help with Project ?
<- previous index next ->