nf_register_hooks NF_HOOK

2024-04-30 14:18
文章标签 register hooks hook nf

本文主要是介绍nf_register_hooks NF_HOOK,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如果我们想加入自己的代码,便要用nf_register_hook函数,其函数原型为:

int nf_register_hook(struct nf_hook_ops *reg)
struct nf_hook_ops://结构
struct nf_hook_ops
{
struct list_head list;
/* User fills in from here down. */
nf_hookfn *hook;
int pf;
int hooknum;
/* Hooks are ordered in ascending priority. */
int priority;
};



hook是提供的处理函数,也就是我们的主要工作,其原型为:


unsigned int nf_hookfn(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,

int (*okfn)(struct sk_buff *));

437          return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
438                         ip_rcv_finish);

我自己做实验,在nf_register_hooks将自己定义的、包含了hook函数,hook点的nf_hook_ops结构体注册到系统中后,一旦有符合条件的包出现,系统都会打印出相应的语句。

  但是在看源码的时候,经常看到有如下的调用方法:        
    return NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, dev, NULL, ip_rcv_finish);

  很不理解。难道 ip_rcv_finish 没有用 nf_register_hooks 注册进系统吗?
  如果注册了,应该就直接到了hook点,该函数就会来检查一次数据包,不用再用NF_HOOK再调用一次啊?

#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)

这样就相当于直接调用 ip_rcv_finish 了


二 NF_HOOK的实现原理
在网卡收到包之后交由ip层处理的时候,就交给了ip_recv函数
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
在做了基本的头校验等工作后,就到了我们的重点NF_HOOK钩子函数,此时还未作路由等路处理
return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL,
ip_rcv_finish);
在做完PRE_ROUTING的筛选后,会执行ip_recv_finish函数,继续执行路由等处理,如果是本地的就会交给更高层的协议进行处理,如果不是交由本地的就执行FORWARD
}
通过NF_HOOK的宏定义可以看到,NF_HOOK主要是调用nf_hook_slow,那么,nf_hook_slow主要做了哪些东西呢?
nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh)

{
elem = &nf_hooks[pf][hook];
next_hook:
verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev,
outdev, &elem, okfn, hook_thresh);
}
nf_interate 的作用就是递归调用注册的钩子函数,
unsigned int nf_iterate(struct list_head *head,struct sk_buff *skb,unsigned int hook,const struct net_device *indev,
const struct net_device *outdev,struct list_head **i,int (*okfn)(struct sk_buff *),int hook_thresh)
{
list_for_each_continue_rcu(*i, head) {
struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
if (hook_thresh > elem->priority)
continue;
repeat:
verdict = elem->hook(hook, skb, indev, outdev, okfn);
if (verdict != NF_ACCEPT) {
#ifdef CONFIG_NETFILTER_DEBUG
if (unlikely((verdict & NF_VERDICT_MASK)
> NF_MAX_VERDICT)) {
NFDEBUG('Evil return from %p(%u).\n',
elem->hook, hook);
continue;
}
#endif
if (verdict != NF_REPEAT)
return verdict;
goto repeat;
}
}
return NF_ACCEPT;
}

Nefilter细节实现分析
Netfilter定义了协议栈中的检查点和检查点上引用的数据结构以及对这些数据
结引用的过程。首先看看在检查点上引用的数据结构,

图中ns_hook_ops就是在检查点上引用的结构。每个协议栈预先定义的8个链表数
组用于保存这些结构,这些链表与协议栈中的检查点一一对应。在实际的应用
中,这8个链表并不一定都被使用,比如在IPV4中,只定义了5个检查点,分别对应前5个链表。
nf_hook_ops结构定义在netfilter.h中,如下:

44 struct nf_hook_ops
45 {
46          struct list_head list;
47 
48          /* User fills in from here down。 */
49          nf_hookfn hook;                           /*   函数指针 */
50          int pf;                                  /*   结构对应的协议栈号*/
51          int hooknum;                         /*   结构对应的检查点号*/
52          /* Hooks are ordered in ascending priority。 */
53          int priority;
54 };
其中有必要先说明一下 其中的一些数据结构,
struct list_head的结构在lish.h中定义,并且在其中定义了一个比较重要的宏:
#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)。
在以后的分析中我们将看到其重要性。

18 struct list_head {
19          struct list_head *next, *prev;
20 };
21 
22 #define LIST_HEAD_INIT(name) { &(name), &(name) }
23 
24 #define LIST_HEAD(name) \
25          struct list_head name = LIST_HEAD_INIT(name) 

然后在nf_hook_ops结构中定义了一个指针函数hook其具体说明将在后面的分析中提及。
这个结构由函数nf_register_hook注册到list_head链表上,链表的索引由结构
中hooknum指定。同一链表上的结构按优先值由小到大排列。在检查点上引用这
些结构时,以它们在链表上的先后顺序引用。其实在这里有一个重要的数组结
构:就是在netfilter.c中定义的全局数组,

47 struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];

说的清楚点就是:比如要在IPV4协议栈上的某一个检查点上注册一个
nf_hook_opts的话,那么其pf即为: PF_INET ,hooknum就为检查点,如
NF_IP_PRE_ROUTING,那么它在这个二维数组中的位置就为nf_hooks[PF_INET]
[NF_IP_PRE_ROUTING]。
那么nf_register_hook是如何工作的呢?

60 int nf_register_hook(struct nf_hook_ops *reg)
61 {
62          struct list_head *i;
63 
64          br_write_lock_bh(BR_NETPROTO_LOCK);
65          for (i = nf_hooks[reg->pf][reg->hooknum].next; 
66               i != &nf_hooks[reg->pf][reg->hooknum]; 
67               i = i->next) {
68             if (reg->priority < ((struct nf_hook_ops *)i)->priority)
69                     break;
70          }
71          list_add(&reg->list, i->prev);
72          br_write_unlock_bh(BR_NETPROTO_LOCK);
73          return 0;
74 } 

用通过把构造好的nf_hook_ops传给函数nf_register_hook,其通过一个循环把这
个结构根据其自身的优先级(priority)插入在nf_hooks[pf][hooknum]链表的相
应的地方。重要的操作就是for循环体中的内容,如果reg->priority的值小于链
表中当前的nf_hook_ops中的优先级时,就立刻跳出循环,执行后来的插入操作.
此处可以看出这个链表上的所有nf_hook_ops结构都是按结构中的priority的值
由小到大的排列,这就为以后的操作提供了方便.插入工作由函数list_add完成,
其实就是一个链表的插入过程。那么当nf_hooks数组链上的结构都已经注册好
了,那下一步该做些什么呢,而且上面提到了检查点,下面看检查点的定义。

我们先看看netfilter_ipv4.h中定义的都有哪些检查点。
39 /* IP Hooks */
40 /* After promisc drops, checksum checks。 */
41 #define NF_IP_PRE_ROUTING        0
42 /* If the packet is destined for this box。 */
43 #define NF_IP_LOCAL_IN           1
44 /* If the packet is destined for another interface。 */
45 #define NF_IP_FORWARD            2
46 /* Packets coming from a local process。 */
47 #define NF_IP_LOCAL_OUT          3
48 /* Packets about to hit the wire。 */
49 #define NF_IP_POST_ROUTING       4
50 #define NF_IP_NUMHOOKS           5            //检查点的数目
实质上检查点的意思就是说当有一个数据包经过此处的话,那么这个数据包先必
须在这些地方做一些检查,如果此检查点觉得没有问题,那么你就继续下面的行
程,如果有问题,将被丢弃,或一些其它的处理。这些检查点是由Netfilter框架加
在协议栈上的,如果在编译内核时,没有定义CONFIG_NETFILTER的话,那么在这些
地方将不对这些数据包做任何处理处理,直接交由后面的部分处理。如果定义了
,那么在这些检查点上就要做一些事情了。Netfilter框架使用了一个巧妙的技
巧,在最大程度上不影响本身的协议。使用NF_HOOK宏来定义这些检查点上的处理
过程,先来看看NF_HOOK宏:

122 #define NF_HOOK(pf, hook, skb, indev, outdev, okfn)   \
123                                         (list_empty(&nf_hooks[(pf)][(hook)])     \
124                                   ? (okfn)(skb)                                         \
125   : nf_hook_slow((pf), (hook), (skb), (indev), (outdev), (okfn))) 

这里又用到了nf_hooks这个数组,首先看到当在nf_hooks[pf][hook]这个链表为
空时,即没有在这个链上用nf_register_hook函数注册任何一个nf_hook_ops结构
时,这个宏就会直接调用由okfn指向的函数做处理,这里先不管okfn指向了什么
地方,也就相当于在这里没有做任何的检查。另外一种情况就是注册了一些nf_hook_ops在这个链表上,那么就会调用下面的这各函数做一些处理,

128 int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
129                struct net_device *indev, struct net_device *outdev,
130                   int (*okfn)(struct sk_buff *));
再看其定义:
449 int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
450                   struct net_device *indev,
451                   struct net_device *outdev,
452                   int (*okfn)(struct sk_buff *))
453 {
454          struct list_head *elem;
455          unsigned int verdict;
456          int ret = 0;
457 
458 /*This stopgap cannot be removed until all the hooks are audited。*/
459          if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) {
460                  kfree_skb(skb);
461                  return -ENOMEM;
462          }
463          if (skb->ip_summed == CHECKSUM_HW) {
464                  if (outdev == NULL) {
465                          skb->ip_summed = CHECKSUM_NONE;
466                  } else {
467                          skb_checksum_help(skb);
468                  }
469          }
470 
471          /* We may already have this, but read-locks nest anyway */
472          br_read_lock_bh(BR_NETPROTO_LOCK);
473 
474 #ifdef CONFIG_NETFILTER_DEBUG
475          if (skb->nf_debug & (1 << hook)) {
476                  printk(“nf_hook: hook %i already set。\n”, hook);
477                  nf_dump_skb(pf, skb);
478          }
479          skb->nf_debug |= (1 << hook);
480 #endif
481 
482          elem = &nf_hooks[pf][hook];
483          verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
484                               outdev, &elem, okfn);
485          if (verdict == NF_QUEUE) {
486                  NFDEBUG(“nf_hook: Verdict = QUEUE。\n”);
487                  nf_queue(skb, elem, pf, hook, indev, outdev, okfn);
488          }
489 
490          switch (verdict) {
491          case NF_ACCEPT:
492                  ret = okfn(skb);
493                  break;
494 
495          case NF_DROP:
496                  kfree_skb(skb);
497                  ret = -EPERM;
498                  break;
499          }
500 
501          br_read_unlock_bh(BR_NETPROTO_LOCK);
502          return ret;
503 }

在最后明显的地方我们就看到了一些重点,看到了一些关键字:NF_ACCEPT,
NF_DROP,从字面的意思很好理解,并且这些值是由一个叫nf_iterate函数的返回
值,这个函数的执行过程也很简单,如下:
  
339 static unsigned int nf_iterate(struct list_head *head,
340                                 struct sk_buff **skb,
341                                 int hook,
342                                 const struct net_device *indev,
343                                 const struct net_device *outdev,
344                                 struct list_head **i,
345                                 int (*okfn)(struct sk_buff *))
346 {
347          for (*i = (*i)->next; *i != head; *i = (*i)->next) {
348                struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
349               switch (elem->hook(hook, skb, indev, outdev, okfn)){

350                  case NF_QUEUE:
351                          return NF_QUEUE;
352 
353                  case NF_STOLEN:
354                          return NF_STOLEN;
355 
356                  case NF_DROP:
357                          return NF_DROP;
358 
359                  case NF_REPEAT:
360                          *i = (*i)->prev;
361                          break;
362 
363 #ifdef CONFIG_NETFILTER_DEBUG
364                  case NF_ACCEPT:
365                          break;
366 
367                  default:
368                          NFDEBUG(“Evil return from %p(%u)。\n”, 
369                                  elem->hook, hook);
370 #endif
371                  }
372          }
373          return NF_ACCEPT;
374 }

         这里看到了一个for循环,其做的就是把这个协议栈上的这个HOOK点
上的所有定义的nf_hook_ops结构遍历一边,并且调用了这个结构中的函数hook指
针,它正是指向我们定义的函数,然后根据这个函数的返回值做进一步的处理,并
且这里有更多的返回值,而在nf_hook_slow函数中只处理了NF_DROP,NF_ACCEPT,
NF_QUEUE。并且看到对不同的返回值,做了一些不同的处理,如果我们定义的函数
返回的是NF_QUEUE,NF_STOLEN,NF_DROP,就立刻返回,如果是NF_REPEAT 只是 改
变一下当前循环中的指针,然后将从新调用我们的注册的处理函数。然而只有所
有这个链表上的注册函数都返回NF_ACCEPT时,这个函数才会返回NF_ACCEPT。

14 /* Responses from hook functions。 */
15 #define NF_DROP 0
16 #define NF_ACCEPT 1
17 #define NF_STOLEN 2
18 #define NF_QUEUE 3
19 #define NF_REPEAT 4
20 #define NF_MAX_VERDICT NF_REPEAT

如果nf_hook_ops结构中我们定义的函数中只要有一个返回NF_DROP或NF_STOLEN
或NF_QUEUE,函数nf_iterate将立即将这个值返回给nf_hook_slow函数,而只有
当我们这个链表上所有nf_hook_ops结构中的hook函数都返回NF_ACCEPT时, 
nf_iterate函数才返回一个NF_ACCEPT给nf_hook_slow函数。
这里我们注意到一个问题,调用我们注册的函数时,是按顺序来取的,这里就是体
现nf_hook_ops结构中优先级的重要性的时候了,当在list_head链表中注册我们
的结构时,是根据其中的优先级来确定位置的,优先级高的处在链表的前面。也就
是说当优先级高的函数返回NF_DROP或NF_STOLEN或NF_QUEUE时,那么后面的函数
将不用做任何处理。只有返回NF_ACCEPT时,低优先级的函数才能做进一步的表
决。
在ns_hook_slow中判断nf_iterate的返回值,如果是NF_ACCEPT,则允许数据包
通过,并将数据包传递给协议栈中的下一个函数;如果是NF_DROP,则释放数据
包,协议栈流程中断;如果是NF_STOLEN,同样中断协议栈的流程,但是没有释
放这个数据包;如果是NF_QUEUE,则将这个包发送到用户空间处理,同时中断协
议栈的流程。现在我们来看看检查点在协议栈中的位置,下图是IPV4中的检查
点:

                 图2 IPV4中的检查点


图中检查点的名称如下:

检查点编号     检查点名称            检查点所在文件名
1              NF_IP_PRE_ROUTING     ip_input.c 
2              NF_IP_LOCAL_IN        ip_input.c 
3              NF_IP_FORWARD         ip_forward.c 
4              NF_IP_POST_ROUTING    ip_output.c 
5              NF_IP_LOCAL_OUT       ip_output.c 

图中,ROUTE(1)处对收到的包做路由查找并判断这个包是需要转发的包还是发往
本机上层的包,ROUTE(2)处查找发出包的路由。NF_IP_PRE_ROUTING处对所有传
入IP层的数据包进行检查,在这之前,有关数据包的版本、长度、校验和等正确
性检查已经完成。NF_IP_LOCAL_IN对发往本机上层的数据包进行检查。
NF_IP_FORWARD处检查需要转发的数据包。NF_IP_POST_ROUTING处对所有向链路
层传递的数据包进行检查,注意在此处数据包的路由已经确定。
NF_IP_LOCAL_OUT对本机发出的包进行检查,此处的路由还没有确定,所以可以
做目的地址转换。实现某个网络安全功能可能需要在多个检查点上注册相应的结
构,在后面的分析中我们可以看到具体的例子。

检查点的作用已经明确,那么下面就来看每个检查点的具体位置。正如上表中显
示的一样,各个检查点分别在上面列出的文件中被HOOK。
首先看NF_IP_PRE_ROUTING检查点,它在ip_input.c中出现的位置只有一处:

int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) 函数中:

376 /*
377   *       Main IP Receive routine。
378   */ 
379 int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
380 {
381          struct iphdr *iph;
382 
383         /* When the interface is in promisc。 mode, drop all the crap
384           * that it receives, do not try to analyse it。
385           */
386          if (skb->pkt_type == PACKET_OTHERHOST)
387                  goto drop;
388 
389          IP_INC_STATS_BH(IpInReceives);
390 
391          if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
392                  goto out;
393 
394          if (!pskb_may_pull(skb, sizeof(struct iphdr)))
395                  goto inhdr_error;
396 
397          iph = skb->nh。iph;
398 
399          /*
400           * RFC1122: 3。1。2。2 MUST silently discard any IP frame that
?         fails the checksum。
401           *
402           *       Is the datagram acceptable?
403           *
404           *       1。       Length at least the size of an ip header
405           *       2。       Version of 4
406           *       3。       Checksums correctly。 [Speed optimisation
?         for later, skip loopback checksums]
407           *       4。       Doesn’t have a bogus length
408           */
409 
410          if (iph->ihl < 5 || iph->version != 4)
411                  goto inhdr_error; 
412 
413          if (!pskb_may_pull(skb, iph->ihl*4))
414                  goto inhdr_error;
415 
416          iph = skb->nh。iph;
417 
418          if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
419                  goto inhdr_error; 
420 
421          {
422                  __u32 len = ntohs(iph->tot_len); 
423                  if (skb->len < len || len < (iph->ihl<<2))
424                          goto inhdr_error;
425 
426      /*Our transport medium may have padded the buffer out.Now we 
427                * know it is IP we can trim to the true length of the frame。
428                * Note this now means skb->len holds ntohs(iph->tot_len)。
429        */
430                  if (skb->len > len) {
431                          __pskb_trim(skb, len);
432                          if (skb->ip_summed == CHECKSUM_HW)
433                                  skb->ip_summed = CHECKSUM_NONE;
434                  }
435          }
436 
437          return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,
438                         ip_rcv_finish);

439 
440 inhdr_error:
441          IP_INC_STATS_BH(IpInHdrErrors);
442 drop:
443          kfree_skb(skb);
444 out:
445          return NET_RX_DROP;
446 }

在437行中我们看到这里调用了前面说明的NF_HOOK宏, 传给它的参数分别是:
PF_INET:IPV4协议栈
NF_IP_PRE_ROUTING: 刚刚讨论的检查点。
skb: sk_buff结构
dev: 输入接口
ip_rcv_finish: okfn指向的后续处理函数。
在调用NF_HOOK之前我们还看到了在这个函数里对这个skb做了一些基本的检查:
如版本,长度,校验和等等。另外的4各HOOK点也在相应的文件里做了相同的处理
,但有一点区别的是,可能一些点上只有输入接口,如: NF_IP_PRE_ROUTING,而有
些只有输出接口,如: NF_IP_POST_ROUTING ,还可能输入输出的接口都有,如: 
NF_IP_FORWARD。

总结
从上面的分析中我们可以看出,一个数据包在经过IPV4这个协议栈做处理时,原则
上其流程是不会因为加入Netfilter框架而改变,Netfilter所要做的事情只不过
是在一些必要的地方看一下这些数据包,并根据用户的意愿对这个数据包处理。
为了更清晰的显示Netfilter框架中的几个HOOK点在IPV4中的位置,可以从下图
中清晰的反映出来。图中椭圆中为处理函数,用箭头指出的函数中的点为调用宏
NF_HOOK处,箭头以为数据包的流程方向。(此处为突出重点,只画出了IP层的大部分和Netfilter密切相关的一些函数)



这篇关于nf_register_hooks NF_HOOK的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/949092

相关文章

【hdu】Just a Hook(线段树区间修改)

线段树模板题,练的是懒惰标记。 懒惰标记,就是更新一段区间的时候,如果小区间被包含在了所需要更新的区间里面,那么直接对代表这个区间的数组元素赋值,之后做一个标记(表示这个区间的子区间都需要更新)但是不继续递归(这样可以节省很多的时候)。 116571152014-09-15 14:17:26Accepted1698796MS2380K1750 BG++KinderRiven #

Netfilter学习之NAT类型动态配置(八)nf_nat_proto_common.c代码解析

nf_nat_proto_common.c实现了对称型的端口改变,在此我决定对其代码进行分析,以便实现对对称型NAT的随意改动。    具体代码如下: #include <linux/types.h>#include <linux/random.h>#include <linux/netfilter.h>#include <linux/export.h>#include <net/n

【C++】win7 64下VC++6.0(Unable to register this add-in because its DLLRegisterServer return an error)

 FileTool.exe用于替换 Visual C++ 使用开发人员 Studio 对象模型中的打开和添加到项目菜单项。也是一个修复 VC6.0打开文件时出错退出的插件。 1. 下载FileTool.exe,并解压 2. 打开VC6.0,点击File-Open Workspace,选择刚解压出来的FileTool.dsw,并确定 3. 点击Bulid-Build FileTool.

react、vue 提供的 hook 函数对比

文章目录 useMemo vs computeduseEffect vs watch useMemo vs computed React 的useMemo 和 Vue3 的computed 分别用于优化性能和避免不必要的计算的两个概念。它们的目标相似,但实现方式和使用场景有所不同。它们都用于优化那些依赖于其他状态或属性,并且计算成本较高的表达式。以下是它们的主要区别: Rea

React学习-hooks

官方文档:https://zh-hans.react.dev/reference/react/useActionState 1.useEffect(setup, dependencies?) 1.1 基础使用 //hooksimport { useEffect } from "react";import "./App.css";function App(){useEffect(()=>{

企业微信hook协议接口,聚合群聊客户管理工具开发

服务提供了丰富的API和SDK,可以在企微的功能之上进行应用开发和功能扩展 自建应用可以调用企微hook或协议提供的接口来实现数据交互,可以直接调用hook或协议接口提供的功能来进行消息的发送与接收、用户管理、应用管理等操作,通过接口可以实现自动回复、定时发送消息等功能,可以用来获取用户信息、添加或删除用户,发送文本消息、图片、文件、语音、视频等多种类型的消息,可以监听特定类型的消息,支持朋友圈

chrome 中class not register解决

刚刚上一篇博客更换帐户名为英文后,chrome的taskbar和开始菜单中的快捷方式一直这个问题。 查了查,说什么要改注册表。 但是chrome.exe可以正常工作,数据也都在。 刚刚发现一个特简单的方法。 在C盘搜索chrome, 删除quicklaunch和startmenu的快捷方式,然后把chrome.exe重新固定到这两个地方就ok了。 不过我之前清理注册表了,不知道这个需不

Android Hook ActivityThread mH 消息

背景: 今天面试被问到如何监听ActivityThread mH 类的消息,当时的想法是,mH 其实就是Handler, Android 没有提供获取到mH 的方法,就算我可以拿到mH 的 Looper, 最多也就可以在Looper 里面设置一个private Printer mLogging; ,当打印的时候就可以知道当前在分发mH 类的任何消息。 但是对方说,不希望在这里拦截,有没有其他方

【精讲】PCIe基础篇——BAR(Base Address Register)详解

一、为什么需要BAR         系统中的每个设备中,对地址空间的大小和访问方式可能有不同的需求,例如,一个设备可能有256字节的内部寄存器/存储,应该可以通过IO地址空间访问,而另一个设备可能有16KB的内部寄存器/存储,应该可以通过基于MMIO的设备访问。哪些地址应该使用哪种方式(IO或Memory)来访问它们的内部位置,这是系统软件(即BIOS和OS内核)的工作。因此设备必须为系统软件

linux内核hook技术之函数地址替换

前言     函数地址替换是一种更为简单、常见的hook方式,比如对security_ops、sys_call_table等结构中的函数进行替换,来完成自己的安全权限控制。     其中security_ops是LSM框架中所使用的,sys_call_table是系统调用表结构。当然了,这些结构目前在内核中都已经是只读数据结构了,如果想直接进行函数替换的话,首先就是考虑解决关闭写保护的问题。在