杭电网安操作系统实验一:Linux 内核编译及添加系统调用


文章较长直接点击以下目录索引即可

一、实验介绍:

本实验通过修改Linux内核源码,添加新的Linux系统调用,替换编译后内核,并测试结果,了解Linux内核源码的编译方法和内核的安装方法,系统调用的概念、编写步骤和调用方法。

二、任务描述:

①掌握Linux 系统调用基本概念
②Linux内核源码的编译和安装
③添加Linux的系统调用
④Linux的系统调用的测试方法

三、具体实验步骤:

(一)实验思路:

在这里插入图片描述

(二)遇到问题及解决办法:

1.在kernel的include\linux路径下的syscalls.h文件中添加代码后,在编译内核中遇到了如下图中的问题
在这里插入图片描述
在通过网上学习知道了,这是由于函数无返回值而产生的报错,将原来代码中的asmlinkage long sys_zlk();改为无返回值函数asmlinkage long sys_zlk(void);便可解决该报错。

2.在添加完各部分的函数之后开始编译内核时,我还遇到了如下图的问题
在这里插入图片描述
这个问题看似报错和上面的很像,但是我怎么也找不到问题所在,最后在询问之下我才知道,完成的同学都是把新加的函数放到了文档末尾,而我则是放在文档开头,抱着试一试的心态,我调整了函数在文档中的位置,果然这一次内核编译成功了。

3.在使用本地虚拟机编译内核的时候,一个典型的问题就是缺各种依赖包,只需下载安装一下各类依赖就能解决了。

(三)核心代码与结果展示:

<1>掌握Linux 内核的编译与安装(任务0)

1.登录系统并查看当前内核版本
输入uname -r
在这里插入图片描述
2. 安装工具,构建开发环境(按序输入如下命令):
yum group install -y "Development Tools"
yum install -y bc
yum install -y openssl-devel
在这里插入图片描述
3.备份boot目录以防后续步骤更新内核失败
tar czvf boot.origin.tgz /boot/
uname –r > uname_r.log
完成以上操作后,ls查看当前目录下的文件会看到两个新增的文件
在这里插入图片描述
3. 获取内核源代码并解压
wget https://gitee.com/openeuler/kernel/repository/archive/kernel-4.19.zip

unzip kernel-4.19.zip
完成以上操作后, ls查看当前目录下的文件会看到两个新增的文件
在这里插入图片描述
5.编译内核
cd kernel
make openeuler_defconfig
看一下编译内核有哪些可配置项,这一步查看了可编译的Image
make help | grep Image
这一步是编译内核的Image、modules和dtbs,make -j 4表示4个线程编译(可以根据CPU核数调整)
make -j4 Image modules dtbs
在这里插入图片描述
6.安装内核
make modules_install
make install
在这里插入图片描述
7.安装好内核之后重启虚拟机便可选择使用新内核了<第一行为新内核,选择进入>
reboot
在这里插入图片描述
4. 登录系统并查看版本uname -r
在这里插入图片描述

<2> 掌握Linux 系统调用基本概念

  1. 把系统调用函数加入到syscalls数组中(操作目录:include/uapi/asm-generic/unistd.h)
/* added by zlk */
#define __NR_zlk 294
__SYSCALL(__NR_zlk, sys_zlk)

在这里插入图片描述
2. 在头文件(include/linux/syscalls.h)中声明系统调用函数

/* added by zlk */
asmlinkage long sys_zlk(void);

3.在kernel/sys.c中添加函数体

/* added by zlk */
SYSCALL_DEFINE0(zlk)
{
		printk(KERN_INFO "姓名:XXX,学号:XXXXXX");
		return 0;
}

4.编译、安装内核

配置内核:make menuconfig
编译内核:make -j64
编译模块:make modules
安装模块:make modules_install
安装内核:make install
立即重启:reboot

5.编写测试代码

#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
int main()
{
		printf("Test sys_zlk:");
		if (syscall(294) == 0)
			printf("success!\n");
		else
			printf("fail!\n");
		return 0;
}

6.编译生成syscall_zlk文件,先用dmesg -c命令清空原有日志后用dmesg查看运行结果

<3>设计和添加系统调用

任务一:修改或返回指定进程的优先级(nice值和prio值)

1.把系统调用函数加入到syscalls数组中(操作目录:include/uapi/asm-generic/unistd.h)

/* added by zlk */
#define __NR_mysetnice 295
__SYSCALL(__NR_mysetnice,sys_mysetnice)

2.在头文件(include/linux/syscalls.h)中声明系统调用函数

/* added by zlk */
asmlinkage long sys_mysetnice(pid_t pid,int flag,int nicevalue,void __user*prio,void __user*nice);

3.在kernel/sys.c中添加函数体

/* added by zlk */ 
SYSCALL_DEFINE5(mysetnice,pid_t,pid,int,flag,int,nicevalue,void __user*,prio,void __user*,nice)
{
	int n;
	int p;
	struct pid * kpid;
	struct task_struct * task;
	kpid = find_get_pid(pid);/*得到pid */
	task = pid_task(kpid, PIDTYPE_PID);/* 返回task_struct */
	n = task_nice(task);/* 返回进程当前nice值 */
	p = task_prio(task);/*返回进程当前prio值*/
	if(flag == 1)
	{
		set_user_nice(task, nicevalue);/* 修改进程nice值 */
		n = task_nice(task);/*重新取得进程nice值*/
		p = task_prio(task);/*重新取得进程prio值*/
		copy_to_user(nice,&n,sizeof(n));/*将nice值拷贝到用户空间*/
		copy_to_user(prio,&p,sizeof(p));/*将prio值拷贝到用户空间*/
		return 0;  
	}
	else if(flag == 0)
	{
		copy_to_user(nice,&n,sizeof(n));/*将nice值拷贝到用户空间*/
		copy_to_user(prio,&p,sizeof(p));/*将prio值拷贝到用户空间*/
		return 0;
	}
	return EFAULT;
}

4.编译、安装内核

配置内核:make menuconfig
编译内核:make -j64
编译模块:make modules
安装模块:make modules_install
安装内核:make install
立即重启:reboot

5.编写测试代码

#define _GNU_SOURCE
#include<unistd.h>
#include<sys/syscall.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
	pid_t pid;
	int nicevalue;
	int flag;
	int n=0;
	int p=0;
	int *prio;
	int *nice;
	prio = &p;
	nice = &n;
	printf("请输入pid: \n");
	scanf("%d",&pid);
	printf("pid输入成功\n请输入nice值:\n");
	scanf("%d",&nicevalue);
	printf("nice输入成功\n请输入flag(flag为1时修改,为0时查看):\n");
	scanf("%d",&flag);
	syscall(295,pid,flag,nicevalue,prio,nice);
	printf("现在的nice为%d,prio为%d\n",n,p);
	return 0;
}

6.编译生成mysetnice.c文件,通过gcc mysetnice.c -o mysetnice生成mysetnice文件后运行./mysetnice

任务二:添加一个新的系统调用,改变主机名称为自定义字符串

1.把系统调用函数加入到syscalls数组中(操作目录:include/uapi/asm-generic/unistd.h)

/* added by zlk */
#define __NR_mysethostname 296
__SYSCALL(__NR_mysethostname,sys_mysethostname)

2.在头文件(include/linux/syscalls.h)中声明系统调用函数

/* added by zlk */
asmlinkage long sys_mysethostname(char __user  *name, int len);

3.在kernel/sys.c中添加函数体

/* added by zlk */ 
SYSCALL_DEFINE2(mysethostname, char __user *, name, int, len)
{
    int errno;
    char tmp[__NEW_UTS_LEN];
    if(len<0 || len>__NEW_UTS_LEN)
        return -EINVAL;
 		   errno = -EFAULT;
    if(!copy_from_user(tmp, name, len))
	{
		struct new_utsname *u;
		down_write(&uts_sem);
		u = utsname();
		mcpy(u->nodename, tmp, len);
		memset(u->nodename + len, 0, sizeof(u->nodename)- len);
		errno = 0;
		uts_proc_notify(UTS_PROC_HOSTNAME);
		up_write(&uts_sem);
	}
	return errno;
}

return -EFAULT; //errno:14 地址错
return -EAGAIN; //errno:11 资源暂时不可用
return -EINTR; //errno:4 中断的函数调用
return -ESPIPE //errno:29 无效的文件指针重定位
return -ENOTTY;//errno:25 不适当的IO控制操作
return -EINVAL;//errno:22 无效的参数

4.编译、安装内核

配置内核:make menuconfig
编译内核:make -j64
编译模块:make modules
安装模块:make modules_install
安装内核:make install
立即重启:reboot

5.编写测试代码

#define _GUN_SOURCE
#include<unistd.h>
#include<sys/syscall.h>
#include<stdio.h>
int main()
{
	syscall(296,"zlkzlk",6);
	return 0;
}

6.编译生成mysethostname.c文件,通过gcc mysethostname.c -o mysethostname生成mysethostname文件后运行./mysethostname

  • 14
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值