# Linux Project 1
## Environment
- Kernel vesion : 5.15.137
- 作業系統 : ubuntu 22.04
## Question Description

## Kernel 編譯過程
下載欲編譯的kernel source code, 新增system call後執行以下指令:
```bash=
sudo make -j4
sudo make modules_install -j4
sudo make install -j4
```
## 編譯時遇到的問題
- 我們有遇到無法編譯成功的情況,發生的問題每次、每個組員都遇到不同問題,但是經過幾次更換版本之後問題就大部分解決了
- 執行sudo make時遇到其中一個問題:"FAILED: load BTF from vmlinux: No such file or directory", 只要下載套件dwarves即可解決
```
sudo apt install dwarves
```
## 新增System Call過程
#### 在linux-5.15.137 directory中創建資料夾vtop, 並在創建的資料夾中新增system call:
```
cd /usr/src/linux-5.15.137
mkdir vtop
cd vtop
vim vtop.c
```
#### 同時創建Makefile並寫入:
```
obj-y := vtop.o
```
#### 接著回上個目錄改 Makefile, 將剛剛新增的資料夾加到路徑中:
```
cd ..
vim Makefile
```

#### 修改syscall_64.tbl:
```
vim arch/x86/entry/syscalls/syscall_64.tbl
```

#### 修改syscalls.h(添加syscall原型)
```
vim include/linux/syscalls.h
```

## System Call
- Linux 在 2.6.10 中引入了四層的頁表輔助虛擬地址的轉換(PGD、PUD、PMD、PTE),在 4.11 中引入了五層的頁表結構(多了一層P4D,也就是:PGD、P4D、PUD、PMD、PTE)。
- 與pud_none(pud_t), pmd_none(pmd_t)不同的是,p4d_none(p4d_t)=True並不一定代表程式出錯,linux kernel會自動幫我們映射到下一層,即回傳(p4d_t)*pgd。
- 依照題目要求,大多system call失敗時會回傳-1,這邊我們改成:失敗return 0,成功則return傳入function之virtual address所對應的physical address。
```C=
#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>
#include <linux/mm_types.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <asm/pgtable.h>
#include <asm/current.h>
SYSCALL_DEFINE1(vtop,unsigned long ,vaddr){
pgd_t *pgd;
p4d_t *p4d;
pud_t *pud;
pmd_t *pmd;
pte_t *pte;
unsigned long p_index=0,p_offset=0;
unsigned long paddr = 0;
printk("va : %lx",vaddr);
pgd = pgd_offset(current->mm,vaddr);
if (pgd_none(*pgd) || pgd_bad (*pgd)){
return 0;
}
p4d = p4d_offset(pgd,vaddr);
if(p4d_bad(*p4d)){
return 0;
}
pud = pud_offset(p4d,vaddr);
if(pud_none(*pud) || pud_bad(*pud)){
return 0;
}
pmd = pmd_offset(pud,vaddr);
if(pmd_none(*pmd) || pmd_bad(*pmd)){
return 0;
}
pte = pte_offset_kernel(pmd,vaddr);
if(!pte){
return 0;
}
p_index = pte_val(*pte) & PAGE_MASK;
p_offset = vaddr & ~PAGE_MASK;
paddr = p_index | p_offset;
printk("pa :%lx",paddr);
return paddr;
}
```
## Multithread.c
```C=
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>
sem_t sem;
__thread int TLS = 0;
int data = 0;
int bss ;
void code(){
return ;
}
void* thread_function(void* thread_num){
sem_wait(&sem);
printf("----------------Thread %d -------------------\n", (int) thread_num);
int stack = 7;
char* sname[] = {"TLS","data","bss","code","stack","heap","lib"};
int *heap = malloc(sizeof(int));
unsigned long linear_address[] = {
(unsigned long) &TLS,
(unsigned long) &data,
(unsigned long) &bss,
(unsigned long) &code,
(unsigned long) &stack,
(unsigned long) heap,
(unsigned long) &printf
};
for(int i=0;i<stack;i++){
unsigned long vaddr = linear_address[i];
unsigned long paddr = syscall(449,vaddr);
printf("%s: Linear address: %#lx , Physical address: %#lx \n", sname[i],vaddr,paddr);
}
sem_post(&sem);
return NULL;
}
void main(){
pthread_t thread1 , thread2, thread3;
sem_init(&sem,0,1);
pthread_create(&thread1, NULL, thread_function, (void*)1);
pthread_create(&thread2, NULL, thread_function, (void*)2);
pthread_create(&thread3, NULL, thread_function, (void*)3);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_join(thread3, NULL);
sem_destroy(&sem);
return;
}
```
### 編譯
```
gcc -o mt multithread.c -pthread
```
## multithread.c 執行結果

## 各Thread在Physical Memory的Layout
### Thread1

### Thread2

### Thread3

## Example Code
- 增加了heap區段
- 加入semaphore,避免thread交互執行導致難以觀察結果
```C=
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <sys/syscall.h> /* Definition of SYS_* constants */
#include <unistd.h>
#include <semaphore.h>
extern void *func1(void *);
extern void *func2(void *);
extern int main();
void * my_get_physical_addresses(void *);
void * my_get_physical_addresses(void *v_addr){
unsigned long vaddr = (unsigned long)v_addr;
unsigned long p_addr = syscall(449, vaddr);
unsigned long *p_ptr = (unsigned long *)p_addr;
return p_ptr;
}
struct data_
{
int id ;
char name[16] ;
};
typedef struct data_ sdata ;
static __thread sdata tx ; //thread local variable
sem_t sem;
int a=123; //global variable
void hello(int pid)
{
int b=10; //local varialbe
int *heap = malloc(sizeof(int)); //heap area
b=b+pid;
//global variable
printf("In thread %d \nthe value of gloable varialbe a is %d, the offset of the logical address of a is %p, ", pid, a, &a);
printf("the physical address of global variable a is %p\n", my_get_physical_addresses(&a) );
//local variable
printf("the value of local varialbe b is %d, the offset of the logical address of b is %p, ", b, &b);
printf("the physical address of local variable b is %p\n", my_get_physical_addresses(&b));
//heap
printf("the value of the logical address of heap area is %p, ", heap);
printf("the physical address of heap area is %p\n", my_get_physical_addresses(heap));
//thread local variable
printf("the offset of the logical address of thread local varialbe tx is %p, ", &tx);
printf("the physical address of thread local variable tx is %p\n", my_get_physical_addresses(&tx));
//function
printf("the offset of the logical address of function hello is %p, ", hello);
printf("the physical address of function hello is %p\n", my_get_physical_addresses(hello));
printf("the offset of the logical address of function func1 is %p, ", func1);
printf("the physical address of function func1 is %p\n", my_get_physical_addresses(func1));
printf("the offset of the logical address of function func2 is %p, ", func2);
printf("the physical address of function func2 is %p\n", my_get_physical_addresses(func2));
printf("the offset of the logical address of function main is %p, ", main);
printf("the physical address of function main is %p\n", my_get_physical_addresses(main));
//library function
printf("the offset of the logical address of library function printf is %p, ", printf);
printf("the physical address of library function printf is %p\n", my_get_physical_addresses(printf));
printf("====================================================================================================================\n");
}
void *func1(void *arg)
{
char *p = (char*) arg ;
int pid ;
pid = syscall( __NR_gettid );
tx.id = pid ;
strcpy(tx.name,p) ;
sem_wait(&sem);
printf("I am thread with ID %d executing func1().\n",pid);
hello(pid);
sem_post(&sem);
while(1)
{
//printf("(%d)(%s)\n",tx.id,tx.name) ;
sleep(1) ;
}
}
void *func2(void *arg)
{
char *p = (char*) arg ;
int pid ;
pid = syscall( __NR_gettid );
tx.id = pid ;
strcpy(tx.name,p) ;
sem_wait(&sem);
printf("I am thread with ID %d executing func2().\n",pid);
hello(pid);
sem_post(&sem);
while(1)
{
//printf("(%d)(%s)\n",tx.id,tx.name) ;
sleep(2) ;
}
}
int main()
{
pthread_t id[2];
sem_init(&sem, 0, 1);
char p[2][16] ;
strcpy(p[0],"Thread1") ;
pthread_create(&id[0],NULL,func1,(void *)p[0]);
strcpy(p[1],"Thread2") ;
pthread_create(&id[1],NULL,func2,(void *)p[1] );
int pid ;
pid = syscall( __NR_gettid );
tx.id = pid ;
strcpy(tx.name,"MAIN") ;
sem_wait(&sem);
printf("I am main thread with ID %d.\n", pid);
hello(pid);
sem_post(&sem);
sem_destroy(&sem);
while(1)
{
//printf("(%d)(%s)\n",tx.id,tx.name) ;
sleep(5) ;
}
}
```
### Example Code 執行結果

## Q&A
#### Q : copy_to_user() and copy_from_user()會有什麼問題?
A : 因為function會將data copy to kernel space,所以如果kernel memory size過小的話會出現問題。
#### Q : system call define方式為何要改變?用舊的會有什麼問題?
A : 詳請請看[Confusion about CVE-2009-0029](https://stackoverflow.com/questions/18885045/confusion-about-cve-2009-0029-linux-kernel-insecure-64-bit-system-call-argument)
#### Q : pthread_create()會call哪一個kernel systemcall?
A : clone()
#### Q : thread是通過何種方式傳遞訊息?
A : signal
#### Q : 為何paging要分4, 5個level? 為何不分2個, 甚至1個?
A : level過少會造成"儲存paging table memory過大"的問題,且多層架構在操作即設計上也比較靈活
## Reference
1. [add a system call教學網址 by 助教](https://hackmd.io/aist49C9R46-vaBIlP3LDA?both)
2. [新增system call](https://hackmd.io/@combo-tw/Linux-%E8%AE%80%E6%9B%B8%E6%9C%83/%2F%40combo-tw%2FBJPoAcqQS#%E5%A6%82%E4%BD%95%E6%96%B0%E5%A2%9E%E4%B8%80%E5%80%8B-System-Call)
3. [Linux轉址以及Virtural Memory](https://iter01.com/510311.html)
4. [Linux Page Tables](https://docs.kernel.org/mm/page_tables.html)
5. [copy_to_user©_from_user](https://blog.51cto.com/u_16087831/6223592)
6. [Linux Project 1](https://staff.csie.ncu.edu.tw/hsufh/COURSES/FALL2023/linux_project_1.html)