简体   繁体   English

在内核模块中获取 NFS 客户端 IP 地址

[英]Get NFS client IP address in a kernel module

I'm working on a kernel module to track the operations performed by NFS clients on my server.我正在开发一个内核模块来跟踪 NFS 客户端在我的服务器上执行的操作。 I can intercept the file operations using a hacky way (hijacking the vfs layer) but I can't retrieve the IP address of the client.我可以使用hacky方式(劫持vfs层)拦截文件操作,但我无法检索客户端的IP地址。

Is there any information that might be stored in the current task that I can use to obtain the IP address of the NFS client performing an operation?是否有任何可能存储在current任务中的信息可用于获取执行操作的 NFS 客户端的 IP 地址?

I know from digging into the source code that nfsd stores a struct nfsd_net in the struct super_block 's s_fs_info field, but I can only retrieve it as a struct net pointer.通过深入研究源代码,我知道 nfsd 在struct super_blocks_fs_info字段中存储了一个struct nfsd_net ,但我只能将它作为struct net指针检索。 And in nfsd's implementation net_generic method is being used to get the struct nfsd_net pointer (using nfsd_net_id which is the pernet_operations 's id ).在 nfsd 的实现中, net_generic方法被用于获取struct nfsd_net指针(使用nfsd_net_id这是pernet_operationsid )。

Can I obtain this id somehow?我可以以某种方式获得这个 id 吗? and if yes, can I use the struct nfsd_net in my kernel module?如果是,我可以在内核模块中使用struct nfsd_net吗? Is it defined somewhere other than the fs/nfsd/netns.h ?它是否在fs/nfsd/netns.h以外的其他地方定义?

Edit编辑

I'm using this approach to hijack the open function.我正在使用这种方法来劫持 open 函数。 I'm writing this for kernel version 4.15.0.我正在为内核版本 4.15.0 编写此代码。 Here's the code of the kernel module:下面是内核模块的代码:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/version.h>
#include <linux/proc_fs.h>
#include <linux/cred.h>
#include <linux/sched.h>
#include <linux/preempt.h>
#include <linux/uaccess.h>
#include <linux/xattr.h>

MODULE_LICENSE("GPL");

#if defined(__i386__)
    #define POFF 1
    #define CSIZE 6
    // push address, addr, ret
    char *jmp_code="\x68\x00\x00\x00\x00\xc3";
    typedef unsigned int PSIZE;
#else
    #define POFF 2
    #define CSIZE 12
    // mov address to register rax, jmp rax. for normal x64 convention
    char *jmp_code="\x48\xb8\x00\x00\x00\x00\x00\x00\x00\x00\xff\xe0";
    typedef unsigned long PSIZE;
#endif

DEFINE_SPINLOCK(root_open_lock);

int (*orig_root_open) (struct inode *, struct file *);
void *orig_root_open_code;

void hook(void *src_func,void *dst_addr){
  barrier();
  write_cr0(read_cr0() & (~0x10000));
  memcpy(src_func,jmp_code,CSIZE);
  *(PSIZE *)&(((unsigned char*)src_func)[POFF])=(PSIZE)dst_addr;
  write_cr0(read_cr0() | 0x10000);
  barrier();
}

void save_and_hook(void **p_reserve,void *src_func,void *dst_addr){
  barrier();
  write_cr0(read_cr0() & (~0x10000));
  *p_reserve=kmalloc(CSIZE,GFP_KERNEL);
  // save origin code
  memcpy(*p_reserve,src_func,CSIZE);
  hook(src_func,dst_addr);
  write_cr0(read_cr0() | 0x10000);
  barrier();
}

void fix(void **p_reserve,void *src_func){
  barrier();
  write_cr0(read_cr0() & (~0x10000));
  memcpy(src_func,*p_reserve,CSIZE);
  write_cr0(read_cr0() | 0x10000);
  barrier();
}

int fake_root_open(struct inode *x, struct file *fp)
{
  int ret;

  printk("vfshijack: hijacked open\n"); // I need to find the client ip here.

  barrier();
  spin_lock(&root_open_lock);
  fix(&orig_root_open_code, orig_root_open);
  ret = orig_root_open(x, fp);
  hook(orig_root_open, fake_root_open);
  spin_unlock(&root_open_lock);
  barrier();
  return ret;
}

int vfs_init(void)
{
  struct file *fp = filp_open("/", O_DIRECTORY|O_RDONLY, 0);
  if (IS_ERR(fp))
    return -1;

  orig_root_open = fp->f_op->open;
  if(orig_root_open)
  {
    save_and_hook(&orig_root_open_code, orig_root_open, fake_root_open);
  }

  filp_close(fp, NULL);

  printk("vfshijack: vfshijack loaded\n");
  return 0;
}

void vfs_exit(void)
{
  if(orig_root_open)
  {
    fix(&orig_root_open_code, orig_root_open);
  }
  printk("vfshijack: vfshijack unloaded\n");
}

module_init(vfs_init);
module_exit(vfs_exit);

You can try to get needed information from linux kernel tracing tools without hooking kernel binary with some custom assembly.您可以尝试从 linux 内核跟踪工具获取所需信息,而无需使用某些自定义程序集挂钩内核二进制文件。 There are perf , ftrace , trace-cmd for most kernel versions, and stap and lttng for more custom versions.大多数内核版本有perfftracetrace-cmd ,更多自定义版本有staplttng Some documentation to start: https://www.kernel.org/doc/html/v4.18/trace/index.html "Linux Tracing Technologies"一些要开始的文档: https : //www.kernel.org/doc/html/v4.18/trace/index.html “Linux Tracing Technologies”

There are several tracepoints defined in nfsd:在 nfsd 中定义了几个跟踪点:

# modprobe nfsd
# modprobe nfs
# perf list tracepoint|grep nfs
# find /sys/kernel/debug/tracing/events -type d|grep nfsd
# trace-cmd list -e nfsd:read_start -F

nfsd/read_start and nfsd/write_start tracepoints are good places to start. nfsd/read_start 和 nfsd/write_start 跟踪点是很好的起点。 Both should have access to request structure rqstp with address rq_addr and fh pointer (but some eBPF or stap scripting may be useful) https://elixir.bootlin.com/linux/v4.15/source/fs/nfsd/vfs.c#L1020两者都应该可以访问带有地址rq_addr和 fh 指针的请求结构rqstp (但一些 eBPF 或 stap 脚本可能有用) https://elixir.bootlin.com/linux/v4.15/source/fs/nfsd/vfs.c #L1020

__be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,...)

    trace_read_start(rqstp, fhp, offset, vlen);

    trace_read_opened(rqstp, fhp, offset, vlen);

    trace_read_io_done(rqstp, fhp, offset, vlen);

    trace_read_done(rqstp, fhp, offset, vlen);

I have no complete example of trace-cmd or stap usage for nfs daemon tracing.我没有用于 nfs 守护进程跟踪的trace-cmd或 stap 使用的完整示例。

Systemtap ( stap ) has some examples of nfsd statistics: https://github.com/jav/systemtap/blob/master/testsuite/systemtap.examples/index.txt Systemtap ( stap ) 有一些 nfsd 统计的例子: https : //github.com/jav/systemtap/blob/master/testsuite/systemtap.examples/index.txt

# stap nfsd_unlink.stp -c "sleep 0.2"
The nfsdtop.stp script gathers and displays NFS lookups

https://github.com/larytet/SystemTap/blob/master/testsuite/systemtap.examples/network/nfsdtop.stp https://github.com/larytet/SystemTap/blob/master/testsuite/systemtap.examples/network/nfsdtop.stp

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM