通过call_usermodehelper()在内核态执行用户程序【转】

转自:http://edsionte.com/techblog/archives/category/linux%E5%86%85%E6%A0%B8%E7%BC%96%E7%A8%8B

背景

如何在Linux内核中执行某些用户态程序或系统命令?在用户态中,可以通过execve()实现;在内核态,则可以通过call_usermodehelpere()实现该功能。如果您查阅了call_usermodehelper()内核函数的源码实现,就可以发现该函数最终会执行do_execve()。而execve系统调用在经历内核的系统调用流程后,也会最终调用do_execve()。

使用举例

1.无输出的可执行文件测试

加载函数demo如下所示:

1 static int __init call_usermodehelper_init(void)
2 {
3     int ret = -1;
4     char path[] = "/bin/mkdir";
5     char *argv[] = {path, "-p", "/home/tester/new/new_dir", NULL};
6  
7     printk("call_usermodehelper module is starting..!\n");
8     ret = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);
9     printk("ret=%d\n", ret);
10     return 0;
11 }

卸载函数demo如下所示:

1 static void __exit call_usermodehelper_exit(void)
2 {
3     int ret = -1;
4     char path[] = "/bin/rm";
5     char *argv[] = {path, "-r", "/home/tester/new", NULL};
6     char *envp[] = {NULL};
7  
8     printk("call_usermodehelper module is starting..!\n");
9     ret = call_usermodehelper(path, argv, envp, UMH_WAIT_PROC);
10     printk("ret=%d\n", ret);
11 }

2.有输出的可执行文件测试

如果该可执行文件有输出,则可以利用输出重定向,不过此时的可执行文件应该是/bin/bash,而实际的可执行文件则称为bash的参数。比如如果想在内核执行ls -la命令,并且将其输出重定向到ls_output中,则在上述的argv[]={“/bin/bash”, “-c”, “ls”, “-la”, “>”, “/home/tester/ls_output”, NULL};

本文虽然说明的是在内核态如何调用用户态程序,不过可以将这种方法抽象一下,看作是内核态主动向用户态发起通信的一种方式。

没有评论 »

发表在Linux内核编程

Tags: 内核态 数据交互 用户态

Linux内核中通过文件描述符获取绝对路径

2014年3月19日

背景

在Linux内核中,已知一个进程的pid和其打开文件的文件描述符fd,如何获取该文件的绝对路径?基本思路是先获取该文件在内核中的file结构体,再通过d_path()获取到整个文件的绝对路径。

方法一

如果理解了进程和文件系统数据结构之间的关系,那么这种方法可以采用。基本的方法如下:

1.通过进程pid获取进程描述符task_struct;

2.通过task_struct获取该进程打开文件结构files_struct,从而获取文件描述符表;

3.以fd为索引在文件描述符表中获取对应文件的结构体file;

4.通过file获取对应path结构,该结构封装当前文件对应的dentry和挂载点;

5.通过内核函数d_path()获取该文件的绝对路径;

通过进程pid获取进程描述符demo:

1 struct task_struct *get_proc(pid_t pid)
2 {
3     struct pid *pid_struct = NULL;
4     struct task_struct *mytask = NULL;
5  
6     pid_struct = find_get_pid(pid);
7     if (!pid_struct)
8         return NULL;
9     mytask = pid_task(pid_struct, PIDTYPE_PID);
10     return mytask;
11 }

通过fd以及d_path()获取绝对路径demo:

1 int get_path(struct task_struct *mytask, int fd)
2 {
3         struct file *myfile = NULL;
4         struct files_struct *files = NULL;
5         char path[100] = {'\0'};
6         char *ppath = path;
7  
8         files = mytask->files;
9         if (!files) {
10                 printk("files is null..\n");
11                 return -1;
12         }
13         myfile = files->fdt->fd[fd];
14         if (!myfile) {
15                 printk("myfile is null..\n");
16                 return -1;
17         }
18         ppath = d_path(&(myfile->f_path), ppath, 100);
19  
20         printk("path:%s\n", ppath);
21         return 0;
22 }

从上面的代码可以看出,从fd到file结构的获取均通过各个数据结构之间的指向关系获取。

方法二

与方法一的思路相同,但是可以直接使用内核提供的函数fget()进行fd到file的获取。这种方法使用比较简单,程序更加安全,不过就是少了对数据结构关系的思考过程。其实也可以将fget()函数的实现过程作为参考,欣赏内核中代码实现的严谨性。

 

Linux内核中通过文件描述符获取绝对路径已关闭评论 »

发表在Linux内核编程

Tags: 内核编程 文件系统 文件路径

libc库和系统调用

2012年6月2日

Linux系统调用这部分经常出现两个词:libc库和封装函数,不知道你是否清楚它们的含义?

libc

libc是Standard C library的简称,它是符合ANSI C标准的一个标准函数库。libc库提供C语言中所使用的宏,类型定义,字符串操作函数,数学计算函数以及输入输出函数等。正如ANSI C是C语言的标准一样,libc只是一种函数库标准,每个操作系统都会按照该标准对标准库进行具体实现。通常我们所说的libc是特指某个操作系统的标准库,比如我们在Linux操作系统下所说的libc即glibc。glibc是类Unix操作系统中使用最广泛的libc库,它的全称是GNU C Library。

类Unix操作系统通常将libc库作为操作系统的一部分,它被视为操作系统与用户程序之间的接口。libc库不仅实现标准C语言中的函数,而且也包含自己所属的函数接口。比如在glibc库中,既包含标准C中的fopen(),又包含类Unix系统中的open()。在类Unix操作系统中,如果缺失了标准库,那么整个操作系统将不能正常运转。

与类Unix操作系统不同的是,Windows系统并不将libc库作为整个核心操作系统的一部分。通常每个编译器都附属自己的libc库,这些libc既可以静态编译到程序中,又可以动态编译到程序中。也就是说应用程序依赖编译器而不是操作系统。

封装函数

在Linux系统中,glibc库中包含许多API,大多数API都对应一个系统调用,比如应用程序中使用的接口open()就对应同名的系统调用open()。在glibc库中通过封装例程(Wrapper Routine)将API和系统调用关联起来。API是头文件中所定义的函数接口,而位于glibc中的封装例程则是对该API对应功能的具体实现。事实上,我们知道接口open()所要完成的功能是通过系统调用open()完成的,因此封装例程要做的工作就是先将接口open()中的参数复制到相应寄存器中,然后引发一个异常,从而系统进入内核去执行sys_open(),最后当系统调用执行完毕后,封装例程还要将错误码返回到应用程序中。

需要注意的是,函数库中的API和系统调用并没有一一对应的关系。应用程序借助系统调用可以获得内核所提供的服务,像字符串操作这样的函数并不需要借助内核来实现,因此也就不必与某个系统调用关联。

不过,我们并不是必须通过封装例程才能使用系统调用,syscall()和_syscallx()两个函数可以直接调用系统调用。具体使用方法man手册中已经说明的很清楚了。

参考:

1. http://en.wikipedia.org/wiki/Libc

2. man syscalls

时间: 2024-08-02 01:25:56

通过call_usermodehelper()在内核态执行用户程序【转】的相关文章

基础:内核态和用户态的区别

当一个任务(进程)执行系统调用而陷入内核代码中执行时,我们就称进程处于内核运行态(或简称为内核态).此时处理器处于特权级最高的(0级)内核代码中执行.当进程处于内核态时,执行的内核代码会使用当前进程的内核栈.每个进程都有自己的内核栈.当进程在执行用户自己的代码时,则称其处于用户运行态(用户态).即此时处理器在特权级最低的(3级)用户代码中运行.当正在执行用户程序而突然被中断程序中断时,此时用户程序也可以象征性地称为处于进程的内核态.因为中断处理程序将使用当前进程的内核栈.这与处于内核态的进程的状

用户态和内核态

(1)用户态和内核态的概念? --->内核态: CPU可以访问内存所有数据, 包括外围设备, 例如硬盘, 网卡. CPU也可以将自己从一个程序切换到另一个程序--->用户态: 只能受限的访问内存, 且不允许访问外围设备. 占用CPU的能力被剥夺, CPU资源可以被其他程序获取 (2)为什么需要用户态和内核态? --->由于需要限制不同的程序之间的访问能力, 防止他们获取别的程序的内存数据, 或者获取外围设备的数据, 并发送到网络, CPU划分出两个权限等级 :用户态 和 内核态 (3)用

Linux内核态抢占机制分析

本文首先介绍非抢占式内核(Non-Preemptive Kernel)和可抢占式内核(Preemptive Kernel)的区别.接着分析Linux下有两种抢占:用户态抢占(User Preemption).内核态抢占(Kernel Preemption).然后分析了在内核态下:如何判断能否抢占内核(什么是可抢占的条件);何时触发重新调度(何时设置可抢占条件);抢占发生的时机(何时检查可抢占的条件);什么时候不能抢占内核.最后分析了2.6kernel中如何支持抢占内核. 1. 非抢占式和可抢占式

多线程之:用户态和内核态的区别

一:大话版用户态和内核态 (1)用户态和内核态的概念? --->内核态: CPU可以访问内存所有数据, 包括外围设备, 例如硬盘, 网卡. CPU也可以将自己从一个程序切换到另一个程序--->用户态: 只能受限的访问内存, 且不允许访问外围设备. 占用CPU的能力被剥夺, CPU资源可以被其他程序获取 (2)为什么需要用户态和内核态? --->由于需要限制不同的程序之间的访问能力, 防止他们获取别的程序的内存数据, 或者获取外围设备的数据, 并发送到网络, CPU划分出两个权限等级 :用

Linux用户态和内核态

转载 - Linux用户态和内核态 作者 digoal 日期 2016-11-20 标签 Linux , 内核态 , 用户态 背景 原文 http://longmans1985.blog.163.com/blog/static/7060547520109262178736/ 原文 1. 用户态和内核态的概念区别 究竟什么是用户态,什么是内核态,这两个基本概念以前一直理解得不是很清楚,根本原因个人觉得是在于因为大部分时候我们在写程序时关注的重点和着眼的角度放在了实现的功能和代码的逻辑性上,先看一个

什么是用户态?什么是内核态?如何区分?

本知识点来自网易云课堂的上课笔记,linux内核分析----中国科学技术大学软件学院:孟宁  一般现代CPU都有几种不同的指令执行级别. 在高执行级别下,代码可以执行特权指令,访问任意的物理地址,这种CPU执行级别就对应着内核态. 而在相应的低级别执行状态下,代码的掌控范围会受到限制.只能在对应级别允许的范围内活动. 举例: intel x86 CPU有四种不同的执行级别0-3,linux只使用了其中的0级和3级分别来表示内核态和用户态.             我想说,对于这个知识我问过我们学

Kernel Mode Linux 3.3_001发布 内核模式执行工具

Kernel Mode Linux 是一款能够在内核模式中执行用户程序的工具.在Linux内核模式中,用户程序可以直接访问内核地址空间.不同于其它的内核模块,用户执行的程序是作为普通进程(除了特权级别),以便调度和分页执行. Kernel Mode Linux 3.3_001该版本合并了3.3 Linux内核. 软件信息:http://www.yl.is.s.u-tokyo.ac.jp/~tosh/kml/ 下载地址:http://www.yl.is.s.u-tokyo.ac.jp/~tosh/

内核态文件操作【转】

转自:http://blog.csdn.net/yf210yf/article/details/8997007 有时候需要在Linux kernel--大多是在需要调试的驱动程序--中读写文件数据.在kernel中操作文件没有标准库可用,需要利用kernel的一些函数,这些函数主 要有: filp_open() filp_close(), vfs_read() vfs_write(),set_fs(),get_fs()等,这些函数在linux/fs.h和asm/uaccess.h头文件中声明.下

gdbserver-linux内核态调试手段问题

问题描述 linux内核态调试手段问题 3C 各位大神,我最近在研究内核调试这一块儿,有诸多疑问,望解答.本人调试的linux内核为运行在Freescale imx53开发板的andorid内核,android4.3.2,linux2.6.35.ubuntu版本为14.04.欲在Ubuntu上搭建一个针对配套的内核调试环境,以实现单步.断点等调试.这几天在网上搜索资料,推荐的内核调试的比较实用的方法有gdb与gdbserver,kgdb,但有诸多疑问,尚未成功.1)gdb与gdbserver这个