⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 系统调用.htm

📁 这是我做linux系统初始化过程分析时在网上收集到的资料
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0059)http://yangxingjun.myrice.com/chinesehow/kernel/node20.html -->
<!--Converted with LaTeX2HTML 98.1 release (February 19th, 1998)originally by Nikos Drakos (nikos@cbl.leeds.ac.uk), CBLU, University of Leeds* revised and updated by:  Marcus Hennecke, Ross Moore, Herb Swan* with significant contributions from:  Jens Lippmann, Marek Rouchal, Martin Wilck and others --><HTML><HEAD><TITLE>系统调用</TITLE>
<META content="System Calls" name=description>
<META content=mpg name=keywords>
<META content=document name=resource-type>
<META content=global name=distribution>
<META http-equiv=Content-Type content="text/html; charset=GB2312"><LINK 
href="C:\Documents and Settings\nonoka\My Documents\系统调用.files\error(2).htm" 
rel=STYLESHEET><LINK href="node21.html" rel=next><LINK href="node19.html" 
rel=previous><LINK href="mpg.html" rel=up><LINK href="node21.html" rel=next>
<META content="MSHTML 6.00.2800.1106" name=GENERATOR></HEAD>
<BODY><!--Navigation Panel--><A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node21.html" 
name=tex2html623><IMG height=24 alt=next src="系统调用.files/next_motif.gif" 
width=37 align=bottom border=0></A> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/mpg.html" 
name=tex2html619><IMG height=24 alt=up src="系统调用.files/error.htm" width=26 
align=bottom border=0></A> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node19.html" 
name=tex2html613><IMG height=24 alt=previous 
src="C:\Documents and Settings\nonoka\My Documents\系统调用.files\error(1).htm" 
width=63 align=bottom border=0></A> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node1.html" 
name=tex2html621><IMG height=24 alt=contents src="系统调用.files/contents_motif.gif" 
width=65 align=bottom border=0></A> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node34.html" 
name=tex2html622><IMG height=24 alt=index src="系统调用.files/index_motif.gif" 
width=43 align=bottom border=0></A> <BR><B>Next:</B> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node21.html" 
name=tex2html624>阻塞进程</A> <B>Up:</B> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/mpg.html" 
name=tex2html620>Linux 内核模块编程</A> <B>Previous:</B> <A 
href="http://yangxingjun.myrice.com/chinesehow/kernel/node19.html" 
name=tex2html614>启动参数</A> <BR><BR><!--End of Navigation Panel-->
<H1><A name=SECTION00900000000000000000>&nbsp;</A><A name=sys-call>&nbsp;</A><A 
name=499>&nbsp;</A> <A name=500>&nbsp;</A> <BR>系统调用 </H1>
<P>迄今为止,我们做的唯一的事就是用好已定义的内核机制去登记 <TT>/proc</TT> 
文件和设备驱动处理程序。如果你想做内核程序员认为你想做的,例如写设备驱动程序,这就对了。但是如果你想做一些不平常的事,在某些地方改变系统的行为呢?那么这大多取决你自己。 

<P>这是内核编程中变得危险的地方。当写下下面的例子,我杀死了 <TT>open</TT> 系统调用。这意味着我不能打开任何文件,不能运行任何程序,甚至不能 
<TT>shutdown</TT> 计算机。我不得不按电源开关。幸运的,没有文件消失。为了确保不失去任何文件,在你做<TT>insmod</TT> 和 
<TT>rmmod</TT>之前请运行 <TT>sync</TT> 。 <A name=507>&nbsp;</A> <A 
name=508>&nbsp;</A> <A name=509>&nbsp;</A> <A name=510>&nbsp;</A> 
<P>忘记 <TT>/proc</TT> 文件,忘记设备文件。它们只是次要的细节。 
所有进程都要使用的和内核通信的真正的方法是系统调用。当一个进程请求内核的服务时(例如打开文件,分支一个新进程,请求更多内存),这是被使用的机制。如果你想改变内核的行为方式,这是你要做的地方。顺便说一下,如果你想看看一个程序使用了什么系统调用,运行 
<TT>strace &lt;命令&gt; &lt;参数列表&gt;</TT>。 <A name=514>&nbsp;</A> 
<P>通常,一个进程不能访问内核。它不能访问内核的内存和调用内核的函数。CPU硬件强迫这个(那就是为什么叫‘保护模式’的原因)。系统调用是对这个通常的规则的例外。所发生的是进程用适当的值填充寄存器然后调用跳到内核中先前已定义的区域的特定的指令(当然,该区域是用户进程可读但不可写的)。在 
Intel CPU下,使用中断 0x80 做这个。硬件知道一旦你跳到这个区域,你就不再是运行在严格的用户模式而是操作系统内核--因此你就可以做任何你想做的。 
<A name=515>&nbsp;</A> 
<P>内核中那个进程可以跳到的区域被称为<TT>system_call</TT>。 
在该区域的程序检查系统调用数,该数告诉内核进程请求什么服务。然后,它在系统调用表(<TT>sys_call_table</TT>)中查找调用的内核函数的地址。然后它调用该函数并在该函数返回后做一些系统检查,再返回那个进程(或者如果该进程的时间运行完了就返回到一个不同的进程)。如果你想读这个代码,它在源文件<TT>arch/</TT>&lt;<TT>architecture</TT>&gt;<TT>/kernel/entry.S</TT>中的 
<TT>ENTRY(system_call)</TT>行后。 <A name=520>&nbsp;</A> <A name=521>&nbsp;</A> <A 
name=522>&nbsp;</A> <A name=523>&nbsp;</A> 
<P>因此,如果你想改变某个系统调用的工作方法,我们所需要做的是写一个自己的函数以实现它(通常是加一些我们的代码然后再调用原来的函数)并且改变 
<TT>sys_call_table</TT> 中的指针指向我们的函数。因为我们可能随后要移除它而我们不想留下一个不稳定的系统,所以在 
<TT>cleanup_module</TT> 中将那个表恢复成原来的状态是很重要的。 
<P>这儿的源代码是这样一个内核模块的例子。我们想“侦察”某个用户,并在该用户打开一个文件的时候 <TT>printk</TT> 
一个信息。朝着这个目标,我们用我们自己的被称为<TT>our_sys_open</TT>的函数代替原来的系统调用去打开文件。这个函数检查当前进程的UID(用户的ID)而如果它等于我们要侦察的UID,它就调用 
<TT>printk</TT>显示要打开的文件名。然后,它用相同的参数调用原来的 <TT>open</TT> 函数做实际的打开文件的工作。 <A 
name=530>&nbsp;</A> 
<P><TT>init_module</TT> 代替<TT>sys_call_table</TT> 中合适的区域并且将原来的指针保存在一个变量中。 
<TT>cleanup_module</TT> 
函数使用该变量将没件事恢复成通常的状态。这个方法是危险的,因为两个内核模块同时改变同一个系统调用是可能的。想象我们有两个内核模块 A 和 B。A 
的打开系统调用将是 A_open 而B 的将是 B_open 。现在,当 A 被插入内核,系统调用被 A_open 代替,当它完成时将调用原来的 
sys_open 。接着,B 被插入内核,它将用 B_open 代替系统调用,当它完成时将调用它认为的原来的系统调用 A_open。 
<P>现在,如果 B 被先移除,所有的事情将是好的--它将简单的恢复系统调用为将恢复原始的系统调用的 A_open。然而,如果A 被移除然后 B 
才被移除,系统将崩溃。A 的移除将恢复系统调用为原始的 sys_open,将 B 排除出那个环。然后,当 B 被移除,它将恢复系统调用为 <B>它</B> 
认为是原始的系统调用的不再存在于内存的 A_open。咋看起来我们好象可以通过检查系统调用是否等于我们的函数及是否根本不去改变它(因此 当 B 
被移除时不会改变系统调用)来解决这个问题,但那会制造更严重的问题。当 A 被移除,看似系统调用变为 B_open ,因此它不再指向 
A_open,因而在它被从内存移除前它不会将它恢复成 sys_open。不幸的, B_open 将仍然试图调用不再存在的 A_open ,因此即使不移除 B 
系统也会崩溃。 <FONT 
color=#ff0000>(译者认为无论是否进行检查,系统都会在A被先移除的情况下在B还未移除时使系统崩溃,因为从作者假设的情况看,B会调用“它”认为的原始的系统调用来完成其功能,在没有检查的情况下,B一样在其存储原系统调用的变量中存储A的函数A_OPEN并进行调用而使系统崩溃。即使B不调用“它”认为的原始的系统调用来完成其功能,系统也会崩溃,因为它无法恢复系统调用。)</FONT> 

<P>我可以想到两个预防的办法。第一个是恢复调用为原始值 sys_open。不幸的, sys_open 不是内核系统表 <TT>/proc/ksyms</TT> 
中的一部分,因此不能访问它。另一个就是使用引用计数来防止一旦模块被加载就可以随便被 
<TT>rmmod</TT>。这对产品模块是一个好办法,但不适合做教育性的范例--这也是我为什么不在这做的原因。 <A 
name=537>&nbsp;</A><A name=538>&nbsp;</A> <A name=539>&nbsp;</A> 
<P>ex <FONT size=+1><B>syscall.c</B></FONT> <A name=544>&nbsp;</A><A 
name=545>&nbsp;</A> 
<P><PRE> 
/* syscall.c 
 * 
 * 系统调用“偷窃”范例
 */


/* Copyright (C) 1998-99 by Ori Pomerantz */


/* 必要头文件 */

/* 标准头文件 */
#include &lt;linux/kernel.h&gt;   /* 内核工作 */
#include &lt;linux/module.h&gt;   /* 明确指定是模块 */

/* 处理 CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include &lt;linux/modversions.h&gt;
#endif        

#include &lt;sys/syscall.h&gt;  /* 系统调用列表 */

/* 为了当前进程结构,我们需要这个知道当前用户是谁 */
#include &lt;linux/sched.h&gt;  




/*  在 2.2.3 版/usr/include/linux/version.h 包含该宏但 2.0.35 不包含
 * 加入以备需要 */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif



#if LINUX_VERSION_CODE &gt;= KERNEL_VERSION(2,2,0)
#include &lt;asm/uaccess.h&gt;
#endif



/* 系统调用表(函数表)。我们只将定义为外部的即可,当我们insmod的时候内核会为我们填充它 */
extern void *sys_call_table[];


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -