编译环境修改任务
基础任务进阶任务 修改准备修改源码
添加系统调用号修改系统调用头文件修改系统调用函数定义 编译安装内核编写主程序进阶任务总结
编译环境虚拟机操作系统: ubuntu-20.04.3-desktop-amd64原系统内核版本:5.11.0-46-generic内核源码版本:5.11.1 修改任务 基础任务
采用内核编译法增加两个系统调用一个系统调用把用户输入的字符串保存到 text.txt 中一个系统调用把 text.txt 中的字符串读出写个主程序调用两个系统调用 进阶任务
用户可以指定用户输入字符串保存的位置和文件名程序可以将系统调用读取出的字符串打印到用户终端 修改准备
下载内核源码掌握内核编译 修改源码
所需修改的文件(路径默认从源码目录开始)如下:
arch/x86/entry/syscalls/syscall_64.tbl //设置系统调用号,如果是32位就用syscall_32.tbl include/linux/syscalls.h //系统调用的头文件 kernel/sys.c //定义系统调用函数
添加系统调用号
使用 gedit 打开 syscall_64.tbl 文件
sudo gedit arch/x86/entry/syscalls/syscall_64.tbl
根据规则在后面添加自己的系统调用号和系统调用名,如下图所示
这里我添加了两个系统调用分别是读和写 修改系统调用头文件
使用 gedit 打开 syscalls.h 文件
sudo gedit include/linux/syscalls.h
添加对应系统调用的函数声明,如下图
asmlinkage long sys_fwrite(int strcount,char __user* string); asmlinkage long sys_fread(void);修改系统调用函数定义
使用 gedit 打开 sys.c 文件
sudo gedit kernel/sys.c
添加对应系统调用的函数定义,内容如下:
//写文件系统调用
SYSCALL_DEFINE2(fwrite,int,strcount,char __user *,string)
{
printk("fwrite executing");
struct file *filp;
char* filename="/usr/src/text.txt ";
printk("open file");
filp = filp_open(filename, O_RDWR|O_TRUNC, 0755);
if(IS_ERR(filp))
{
printk("open error...n");
return -1;
}
printk("writingn");
char* buf;
buf = (char *)kmalloc(sizeof(char) * strcount, GFP_KERNEL);
if(!copy_from_user(buf, string, strcount))
{
printk("input is %s n", buf);
}
kernel_write(filp, buf, strlen(buf),&filp->f_pos);
filp_close(filp,NULL);
printk("fwrite endn");
return 0;
}
// 读文件系统调用
SYSCALL_DEFINE0(fread)
{
printk("fread executing");
struct file *filp;
struct inode *inode;
const char* filename="/usr/src/text.txt ";
off_t fsize;
char *buf;
unsigned long magic;
printk("start....n");
filp=filp_open(filename,O_RDONLY,0);
inode=file_inode(filp);
magic=inode->i_sb->s_magic;
printk("file system magic:%li n",magic);
printk("super blocksize:%li n",inode->i_sb->s_blocksize);
printk("inode %li n",inode->i_ino);
fsize=inode->i_size;
printk("file size:%i n",(int)fsize);
buf=(char *) kmalloc(fsize+1,GFP_ATOMIC);
printk("buf correctn");
kernel_read(filp,buf,fsize,&(filp->f_pos));
buf[fsize]=' ';
printk("The File Content is:n");
printk("%sn",buf);
filp_close(filp,NULL);
printk("fread endn");
return 0;
}
将两个函数定义写在 sys.c 文件的尾部
其中 SYSCALL_DEFINE 为系统定义,之后的数字代表系统调用参数的个数,其中第一个参数为系统调用函数的名称,需要与调用号定义(调用号定义第三个参),声明(sys_xxx中xxx部分)一致。注意系统调用定义时的参数书写格式。
编译安装内核
#编译内核 sudo make -j4 #安装内核模块 sudo make modules_install #安装内核 sudo make install #重启 reboot编写主程序
在指定目录下新建文件 text.txt
sudo touch /usr/src/text.txt
新建 readAndWrite.c 文件,内容如下
#include#include #include #include #include int main() { long int a; printf("this is testwr executionn"); char string[120]; scanf("%s",string); int length=strlen(string)+1; a = syscall(442,length,string); printf("a=%lin",a); printf("testwr endn"); printf("this is testwr executionn"); a = syscall(443); printf("a=%lin",a); printf("testwr endn"); return 0; }
编译
gcc readAndWrite.c -o readAndWrite.o
执行
sudo ./readAndWrite.o
执行结果,如下图
至此基础任务完成,接下来完成进阶任务
进阶任务
重新添加新的系统调用
添加系统调用号
添加系统调用函数声明
asmlinkage long sys_fsize(int pathcount,char __user * path); asmlinkage long sys_fwrite_advance(int strcount,char __user * string,int pathcount,char __user * path); asmlinkage long sys_fread_advance(char __user * res,int pathcount,char __user * path);
添加系统调用函数定义
//获取文件大小系统调用
SYSCALL_DEFINE2(fsize,int,pathcount,char __user *,path)
{
printk("fsize executing");
struct file *filp;
struct inode *inode;
off_t fsize;
unsigned long magic;
char* pathbuf;
pathbuf = (char *)kmalloc(sizeof(char) * pathcount, GFP_KERNEL);
if(!copy_from_user(pathbuf, path, pathcount))
{
printk("input path is %s n", pathbuf);
}
printk("start....n");
filp=filp_open(pathbuf,O_RDONLY,0);
inode=file_inode(filp);
magic=inode->i_sb->s_magic;
printk("file system magic:%li n",magic);
printk("super blocksize:%li n",inode->i_sb->s_blocksize);
printk("inode %li n",inode->i_ino);
fsize=inode->i_size;
printk("file size:%i n",(int)fsize);
filp_close(filp,NULL);
printk("fsize endn");
return fsize+1;
}
//写文件系统调用
SYSCALL_DEFINE4(fwrite_advance,int,strcount,char __user *,string,int,pathcount,char __user *,path)
{
printk("fwrite_advance executing");
struct file *filp;
char* pathbuf;
pathbuf = (char *)kmalloc(sizeof(char) * pathcount, GFP_KERNEL);
if(!copy_from_user(pathbuf, path, pathcount))
{
printk("input path is %s n", pathbuf);
}
printk("%s",pathbuf);
printk("open file");
filp = filp_open(pathbuf, O_RDWR|O_TRUNC, 0755);
if(IS_ERR(filp))
{
printk("open error...n");
return -1;
}
printk("writingn");
char* buf;
buf = (char *)kmalloc(sizeof(char) * strcount, GFP_KERNEL);
if(!copy_from_user(buf, string, strcount))
{
printk("input is %s n", buf);
}
kernel_write(filp, buf, strlen(buf),&filp->f_pos);
filp_close(filp,NULL);
printk("fwrite_advance endn");
return 0;
}
//读文件系统调用
SYSCALL_DEFINE3(fread_advance,char __user *,res,int,pathcount,char __user *,path)
{
printk("fread_advance executing");
struct file *filp;
struct inode *inode;
off_t fsize;
char *buf;
unsigned long magic;
char* pathbuf;
pathbuf = (char *)kmalloc(sizeof(char) * pathcount, GFP_KERNEL);
if(!copy_from_user(pathbuf, path, pathcount))
{
printk("input path is %s n", pathbuf);
}
printk("start....n");
filp=filp_open(pathbuf,O_RDONLY,0);
inode=file_inode(filp);
magic=inode->i_sb->s_magic;
printk("file system magic:%li n",magic);
printk("super blocksize:%li n",inode->i_sb->s_blocksize);
printk("inode %li n",inode->i_ino);
fsize=inode->i_size;
printk("file size:%i n",(int)fsize);
buf=(char *) kmalloc(fsize+1,GFP_ATOMIC);
printk("buf correctn");
kernel_read(filp,buf,fsize,&(filp->f_pos));
buf[fsize]=' ';
printk("The File Content is:n");
printk("%sn",buf);
if(!copy_to_user(res, buf, fsize+1))
{
printk("output success");
}
filp_close(filp,NULL);
printk("fread_advance endn");
return 0;
}
编译安装内核修改主程序
#include#include #include #include #include #include int main() { long int a; printf("this is testwr executionn"); char *res; char string[120]; char path[120]; scanf("%s",string); scanf("%s",path); int length=strlen(string)+1; int plength=strlen(path)+1; a = syscall(444,length,string,plength,path); printf("a=%lin",a); printf("testwr endn"); printf("this is testwr executionn"); a = syscall(446,plength,path); printf("a=%lin",a); res = malloc(sizeof(char)*a); a = syscall(445,res,plength,path); printf("%sn",res); printf("a=%lin",a); printf("testwr endn"); return 0; }
在所需目录下新建所需文件编译运行,结果如下
总结
增加系统调用主要是修改三个文件,分别添加系统调用号、系统调用函数声明和系统调用函数定义增加文件读写系统调用的核心函数是:filp_open、filp_close、kernel_read、kernel_write、copy_from_user、copy_to_user关于文件读写和系统调用传参最大且最容易出现的问题往往是字符指针和字符数组的问题



