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

📄 11.html

📁 linux操作系统内核编程-----LINUX系统开发非常好的资料
💻 HTML
字号:
<html><head><title>黄金书屋</title><meta http-equiv="Content-Type" content="text/html; charset=gb2312"><link rel="stylesheet" href="/goldnets.css"></head><body bgcolor="#E4EBF1"><center><a href="http://ad.myrice.com/RealMedia/ads/click_nx.ads/goldnets.myrice.com/banner1@Top" target=_blanck ><script language=JavaScript><!---todayd = new Date();var seconds = todayd.getTime();document.write("<img src=\"http://ad.myrice.com/RealMedia/ads/adstream_nx.ads/goldnets.myrice.com/banner1@Top?dd=seconds\" border=0 width=468 height=60>");//--></script></a></center><br><table width="756" border="0" cellspacing="0" cellpadding="0" align="center" bgcolor="#E4EBF1">  <tr>    <td colspan="2" valign="top" align="center">      <div align="center">        <table width="100%" border="0" cellspacing="0" cellpadding="0" height="52">          <tr>            <td valign="top"><br>              <div align="center">                <table width="100%" border="0" cellspacing="0" cellpadding="0">                  <tr>                    <td valign="bottom">                      <table width="100%" border="0" cellspacing="0" cellpadding="0">                        <tr>                          <td><a href="/index.html">首页</a>&gt;&gt; <font color="#CC0000"><a href="/book/152/1015178.html">Linux内核编程</a></font></td>                          <td width="22%"> <a href="/index.html">[ 点此回首页 ]</a></td>                        </tr>                        <tr>                          <td colspan="2"><img src="/image/1x1.gif" width="1" height="2"></td>                        </tr>                        <tr bgcolor="#FFCC00">                          <td colspan="2"><img src="/image/1x1.gif" width="1" height="1"></td>                        </tr>                        <tr>                          <td colspan="2"><img src="/image/1x1.gif" width="1" height="6"></td>                        </tr>                      </table>                    </td>                  </tr>                </table>                <br>                <table width="590" border="0" cellspacing="0" cellpadding="0">                  <tr>                    <td><center><a href='10.html'>上一页 </a>||<a href='12.html'>下一页</a></center><br><hr><div style=font-size:12pt><pre>                               7.系统调用
到此为止,我们做的事情就是使用定义好的内核机制来注册/proc文件和设备句柄。这
在做内核常规处理的事情时是很理想的。但是如果你希望做一些非常规的事情、改变系统的
行为的时候该怎么办呢?这就必须依靠自己。
这就是内核编程变得危险的地方。在写下面的例子的时候,我关闭了open系统调用。
这意味着我不能打开任何文件,不能运行任何程序,而且不能关闭计算机。我必须拉住电源
开关。幸运的是,没有文件丢失。为确保你也不会丢失任何文件,在做insmod以及rmmod
前请执行sync权限,
忘记/proc文件,忘记设备文件。它们只是不重要的细节。真正的同内核通信的过程机
制是被所有进程公用的,这就是系统调用。当一个进程请求内核服务时(比如打开文件、创
建一个新进程或者要求更多内存),就需要使用这个机制。如果你想用比较有趣的方法改变
内核行为,这就是你所需要的。另外,如果你希望看到程序使用了哪一个系统调用,运行
strace <command> <arguments>。
一般的,进程是不能访问内核的。它不能访问内核所占内存空间也不能调用内核函数。
CPU硬件决定了这些(这就是为什么它被称作“保护模式”)。系统调用是这些规则的一个
例外。其原理是进程先用适当的值填充寄存器,然后调用一个特殊的指令,这个指令会跳到
一个事先定义的内核中的一个位置(当然,这个位置是用户进程可读但是不可写的)。在Intel 
CPU中,这个由中断0x80实现。硬件知道一旦你跳到这个位置,你就不是在限制模式下运
行的用户,而是作为操作系统的内核——所以你就可以为所欲为。
进程可以跳转到的内核位置叫做sysem_call。这个过程检查系统调用号,这个号码告诉
内核进程请求哪种服务。然后,它查看系统调用表(sys_call_table)找到所调用的内核函数入
口地址。接着,就调用函数,等返回后,做一些系统检查,最后返回到进程(或到其他进程,
如果这个进程时间用尽)。如果你希望读这段代码,它在源文件目录
/<architecture>/kernel/entry.S,Entry(system_call)的下一行。
所以,如果我们希望改变某个系统调用的工作方式,我们需要写我们自己的函数(通
常是加一点我们自己的代码然后调用原来的函数)来实现,然后改变sys_call_table中的指
针使其指向我们的函数。因为我们可能以后会删除,而且不希望系统处在不稳定状态,所以
在cleanup_module中保存该表的原来状态很重要。
这里的源代码是一个这样的核心模块的例子。我们希望“窥探”一个用户,每当这个
用户打开一个文件是就printk一条消息。为达到这个目的,我们把打开文件的系统调用替换
为我们自己的函数,our_sys_open。这个函数检查当前进程的uid(用户的id),如果它等于
我们要窥探的uid,就调用printk来显示所打开文件的文件名。然后,可以用任何一种方法,
用同样的参数调用原来的open函数,或者真正打开文件。	
Init_module函数把sys_call_table中的适当地址上的内容替换,把原来的指针保存在一
个变量里。Cleanup_module函数用这些变量恢复所有的东西。这种方法是危险的,因为两
个内核模块可能改变了同一个系统调用。设想我们由两个内核模块,A和B。A的open系
统调用是A_open,B的open系统调用是B_open。现在,如果A插入内核,系统调用将被
替换为A_open,当完成以后调用sys_open。然后,B被插入内核,把系统调用替换为B_open,
而完成的时候,它将会调用它认为原始的系统调用的A_open,。
那么,如果B被首先删除,不会出现任何错误——它只是把系统调用恢复成A_open,
A_open再去调用原始的的系统调用。然而,如果先删除A,再删除B,系统就会崩溃。A
的删除将会把系统调用恢复成sys_open,而把B切换出了循环。然后,当B被删除时,将
会把系统调用恢复成A_open,但是A_open已经不在内存。初看来,似乎我们可以通过检
查系统调用是否等于我们的open函数来解决这个问题,如果是就不要改变它(这样B被删
除的时候就不会改变系统调用),但是这样会引起一个更加恶劣的问题。当A被删除时,它
看到系统调用被改成了B_open而不再指向A_open,所以在它被删除时就不会恢复sys_open。
不幸的是,B_open仍然试图恢复A_open,但它已不再内存,这样,即使没有删除B系统也
会崩溃。
我可以提出两个方法来解决这个问题。第一个方法是把调用恢复成原始值,sys_open。
不幸的是sys_open不是在/proc/ksyms中的内核系统表中的一部分,所以我们不能访问它。
另一个解决办法是使用索引计数器来阻止root 去rmmod这个模块,一旦它被装载。这在生
产性模块中是好的,但是对教学里中不是很好——这就是为什么我不在这里这样做。
ex syscall.c    
 
/* syscall.c 
 * 
 * System call \"stealing\" sample
 */


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


/* The necessary header files */

/* Standard in kernel modules */
#include <linux/kernel.h>   /* We\'re doing kernel work */
#include <linux/module.h>   /* Specifically, a module */

/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif        

#include <sys/syscall.h>  /* The list of system calls */

/* For the current (process) structure, we need
 * this to know who the current user is. */
#include <linux/sched.h>  




/* In 2.2.3 /usr/include/linux/version.h includes a 
 * macro for this, but 2.0.35 doesn\'t - so I add it 
 * here if necessary. */
#ifndef KERNEL_VERSION
#define KERNEL_VERSION(a,b,c) ((a)*65536+(b)*256+(c))
#endif



#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
#include <asm/uaccess.h>
#endif



/* The system call table (a table of functions). We 
 * just define this as external, and the kernel will 
 * fill it up for us when we are insmod\'ed 
 */
extern void *sys_call_table[];


/* UID we want to spy on - will be filled from the 
 * command line */
int uid;  

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
MODULE_PARM(uid, \"i\");
#endif

/* A pointer to the original system call. The reason 
 * we keep this, rather than call the original function 
 * (sys_open), is because somebody else might have 
 * replaced the system call before us. Note that this 
 * is not 100% safe, because if another module 
 * replaced sys_open before us, then when we\'re inserted 
 * we\'ll call the function in that module - and it 
 * might be removed before we are.
 *
 * Another reason for this is that we can\'t get sys_open.
 * It\'s a static variable, so it is not exported. */
asmlinkage int (*original_call)(const char *, int, int);



/* For some reason, in 2.2.3 current->uid gave me 
 * zero, not the real user ID. I tried to find what went 
 * wrong, but I couldn\'t do it in a short time, and 
 * I\'m lazy - so I\'ll just use the system call to get the 
 * uid, the way a process would. 
 *
 * For some reason, after I recompiled the kernel this 
 * problem went away. 
 */
asmlinkage int (*getuid_call)();



/* The function we\'ll replace sys_open (the function 
 * called when you call the open system call) with. To 
 * find the exact prototype, with the number and type 
 * of arguments, we find the original function first 
 * (it\'s at fs/open.c). 
 *
 * In theory, this means that we\'re tied to the 
 * current version of the kernel. In practice, the 
 * system calls almost never change (it would wreck havoc 
 * and require programs to be recompiled, since the system
 * calls are the interface between the kernel and the 
 * processes).
 */
asmlinkage int our_sys_open(const char *filename, 
                            int flags, 
                            int mode)
{
  int i = 0;
  char ch;

  /* Check if this is the user we\'re spying on */
  if (uid == getuid_call()) {  
   /* getuid_call is the getuid system call, 
    * which gives the uid of the user who
    * ran the process which called the system
    * call we got */

    /* Report the file, if relevant */
    printk(\"Opened file by %d: \", uid); 
    do {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
      get_user(ch, filename+i);
#else
      ch = get_user(filename+i);
#endif
      i++;
      printk(\"%c\", ch);
    } while (ch != 0);
    printk(\"\\n\");
  }

  /* Call the original sys_open - otherwise, we lose 
   * the ability to open files */
  return original_call(filename, flags, mode);
}



/* Initialize the module - replace the system call */
int init_module()
{
  /* Warning - too late for it now, but maybe for 
   * next time... */
  printk(\"I\'m dangerous. I hope you did a \");
  printk(\"sync before you insmod\'ed me.\\n\");
  printk(\"My counterpart, cleanup_module(), is even\"); 
  printk(\"more dangerous. If\\n\");
  printk(\"you value your file system, it will \");
  printk(\"be \\\"sync; rmmod\\\" \\n\");
  printk(\"when you remove this module.\\n\");

  /* Keep a pointer to the original function in 
   * original_call, and then replace the system call 
   * in the system call table with our_sys_open */
  original_call = sys_call_table[__NR_open];
  sys_call_table[__NR_open] = our_sys_open;

  /* To get the address of the function for system 
   * call foo, go to sys_call_table[__NR_foo]. */

  printk(\"Spying on UID:%d\\n\", uid);

  /* Get the system call for getuid */
  getuid_call = sys_call_table[__NR_getuid];

  return 0;
}


/* Cleanup - unregister the appropriate file from /proc */
void cleanup_module()
{
  /* Return the system call back to normal */
  if (sys_call_table[__NR_open] != our_sys_open) {
    printk(\"Somebody else also played with the \");
    printk(\"open system call\\n\");
    printk(\"The system may be left in \");
    printk(\"an unstable state.\\n\");
  }

  sys_call_table[__NR_open] = original_call;
}</pre><hr><br><center><a href='10.html'>上一页 </a>||<a href='12.html'>下一页</a></center></div> </td>                  </tr>                </table>                <p>&nbsp; </p>                </div>            </td>          </tr>        </table>          <br>          <table border="0" width="75%"><tr><td align="right"><a href="/"><img src="/image2/logo_bottom.gif" border="0"></a></td></tr></table>          <hr size="1" align="center" color="#eecccc">          <br>        </div>      </div>      </td>  </tr></table>  <center><a href="http://ad.myrice.com/RealMedia/ads/click_nx.ads/goldnets.myrice.com/banner1@Bottom" target=_blanck ><script language=JavaScript><!---todayd = new Date();var seconds = todayd.getTime();document.write("<img src=\"http://ad.myrice.com/RealMedia/ads/adstream_nx.ads/goldnets.myrice.com/banner1@Bottom?dd=seconds\" border=0 width=468 height=60>");//--></script></a></center></body></html>

⌨️ 快捷键说明

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