zoukankan      html  css  js  c++  java
  • linux内核中的const成员是否可以修改?

    本文的基础知识:由于前半部分内容是转的,且不知道原文出处,没法给出原文地址,大家自行百度

    const的实现机制

    const究竟是如何实现的呢?对于声明为const的内置类型,例如int,short,long等等,编译器会如何实现const的本意?那么对于非内置类型是否也是与内置数据类型一样处理呢,例如对于结构体类型则会怎样处理呢?下面通过几个小例子来说明这些问题:
    C语言const示例:


    const int i=10;
    int *p=(int *)(&i);
    *p=20;
    printf("i=%d *p=%d ",i,*p);


    猜一猜输出结果是什么? i=20 *p=20
    C++语言const示例1:


    const int i=10;
    int *p=const_cast<int *>(&i);
    *p=20;

    cout<<"i="<<i<<"*p="<<*p<<endl;


    输出结果是 i=10 *p=20
    C++语言const示例2:


    struct test{
    int j;
    char tmp;
    test()
    {
    j=30;
    tmp='a';
    }
    };
    int main(int argc, char* argv[])
    {
    const struct test t1;
    int *q=(int *)(&t1.j);
    *q=40;
    cout<<"j="<<t1.j<<"*q="<<*q<<endl;
    return 0;
    }


    输出结果是 j=40 *q=40

    示例结果分析
    看到上面三组输出结果,我们可以分析两个问题:

    问题1:C语言和C++语言中的const究竟表示什么?

    问题2:const的实现机制究竟是怎样的?

     
    问题1,对于const int类型的变量i,C语言中通过指针p修改了值后,i变成了20;而在C++中,通过指针p修改了值后,i仍然是10。
    问题2,C++语言中 const struct test的元素j通过指针q被改变了,为何const int 与 const struct test的反应机制不同?

    针对问题1,我们知道C语言中const表示只读的变量,既然把const看成是变量,那么其在内存中就会有存储他的空间,并且可以通过指针间接的改变该内存空间的值,当通过指针p改变该内存中的值后,再获取i的值的时候,会访问该空间,得到的是被改变后的值。而C++把const看做常量,编译器会使用常数直接替换掉对i的引用,例如cout<<i; 会理解成cout<<10; 并不会去访问i的内存地址去取数据,这里有点像是C语言里的宏#define i 10。因此C++里i会输出10,而*p会输出20.

    针对问题2,C++语言中只是对于内置数据类型做常数替换,而对于像结构体这样的非内置数据类型则不会。因为结构体类型不是内置数据类型,编译器不知道如何直接替换,因此必须要访问内存去取数据,而访问内存去取数据必然会取到被指针q改变后的值,因此会造成与C++中const int类型完全不一样的处理模式。

    -------------------------------------------------------------------------------------------分割线---------------------------------------------------------------------------------------------------

    有了这个背景知识,我们来看一下如何替换一个内核函数:

    const struct file_operations xfs_file_operations = {
        .llseek     = xfs_file_llseek,
        .read       = do_sync_read,
        .write      = do_sync_write,
        .aio_read   = xfs_file_aio_read,
        .aio_write  = xfs_file_aio_write,
        .splice_read    = xfs_file_splice_read,
        .splice_write   = xfs_file_splice_write,
        .unlocked_ioctl = xfs_file_ioctl,
    #ifdef CONFIG_COMPAT
        .compat_ioctl   = xfs_file_compat_ioctl,
    #endif
        .mmap       = xfs_file_mmap,
        .open       = xfs_file_open,
        .release    = xfs_file_release,
        .fsync      = xfs_file_fsync,
        .fallocate  = xfs_file_fallocate,
    };
     
    p_xfs_file_operations =(struct file_operations*)kallsyms_lookup_name("xfs_file_operations");
    pte_xfs_splice = lookup_address((unsigned long)p_xfs_file_operations, &level);
    // change PTE to allow writing
    set_pte_atomic(pte_xfs_splice, pte_mkwrite(*pte_xfs_splice));
    
    orig_xfs_file_splice_read = p_xfs_file_operations->splice_read;
    p_xfs_file_operations->splice_read = caq_xfs_file_splice_read;
    set_pte_atomic(pte_xfs_splice, pte_clear_flags(*pte_xfs_splice, _PAGE_RW));
    该变量是一个const变量,假设我们要替换splice_read    成员,如果直接修改,肯定不行,转成指针,就ok了,这样,我就把splice_read  成功地改为了自己的函数。

    如果如果没有 set_pte_atomic(pte_xfs_splice, pte_mkwrite(*pte_xfs_splice)); 这行代码会怎么样?

    答案是,如果当时这个页没有写权限,肯定会出crash,如果有的话,这行代码就没用,但是

    set_pte_atomic(pte_xfs_splice, pte_clear_flags(*pte_xfs_splice, _PAGE_RW));
    

      这行代码就会有问题,因为后面可能有人去写这个页的时候就会crash。出现crash,打印一般如下:

    <1>[51178.495137] BUG: unable to handle kernel paging request at ffffffffa0671ab8
    <1>[51178.495150] IP: [<ffffffffa06cb312>] replace_sendfile+0x2c2/0x300 [newsendfile]
    <4>[51178.495163] PGD 1a0b067 PUD 1a0f063 PMD 391bf00067 PTE 800000391bea7161
    <0>[51178.495173] Oops: 0003 [#1] SMP
    <4>[51178.495179] CPU 0
    <4>[51178.495181] Modules linked in: newsendfile(EN+) datalink(EN) xfs w83627dhg(EN) tipc(EX) ossmod(EN) witdriver(EN) bonding ip6table_filter ip6_tables iptable_filter ip_tables ebtable_nat ebtables x_tables af_packet ipmi_devintf ipmi_si ipmi_msghandler edd cpufreq_conservative cpufreq_userspace cpufreq_powersave acpi_cpufreq mperf fuse loop dm_mod vhost_net macvtap macvlan ipv6 ipv6_lib tun kvm_intel kvm pcspkr ses enclosure usbhid hid i40e(EX) sg igb i2c_i801 iTCO_wdt iTCO_vendor_support dca mei mptctl ptp mptbase pps_core rtc_cmos acpi_power_meter container button ext3 jbd mbcache ttm drm_kms_helper drm i2c_algo_bit sysimgblt sysfillrect i2c_core syscopyarea ehci_hcd usbcore usb_common sd_mod crc_t10dif processor thermal_sys hwmon scsi_dh_hp_sw scsi_dh_alua scsi_dh_rdac scsi_dh_emc scsi_dh mpt3sas(EX) configfs scsi_transport_sas raid_class scsi_mod
    <4>[51178.495291] Supported: No, Unsupported modules are loaded
    <4>[51178.495295]
    <4>[51178.495300] Pid: 24329, comm: insmod Tainted: G           ENX 3.0.101-0.47.90-default #1 ZTE Grantley/S1008
    <4>[51178.495309] RIP: 0010:[<ffffffffa06cb312>]  [<ffffffffa06cb312>] replace_sendfile+0x2c2/0x300 [newsendfile]
    <4>[51178.495321] RSP: 0018:ffff88190f2b7ee8  EFLAGS: 00010286
    <4>[51178.495325] RAX: ffffffffa0661b10 RBX: ffffffff81bd5160 RCX: ffff880001a0bff0
    <4>[51178.495330] RDX: ffffffffa0671a00 RSI: ffffffffa06cf4d4 RDI: ffffffffa06cd150
    <4>[51178.495335] RBP: ffffffffa069e880 R08: 000000391bf00000 R09: ffff880000000000
    <4>[51178.495340] R10: 00000000000926bc R11: 00000000ffffffff R12: ffffffffa014c000
    <4>[51178.495345] R13: 0000000000000000 R14: 00007ffc45684787 R15: 00007fcc25041010
    <4>[51178.495351] FS:  00007fcc25104700(0000) GS:ffff88207fc00000(0000) knlGS:0000000000000000
    <4>[51178.495357] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
    <4>[51178.495361] CR2: ffffffffa0671ab8 CR3: 0000001f177bc000 CR4: 00000000001407f0
    <4>[51178.495366] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
    <4>[51178.495371] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
    <4>[51178.495377] Process insmod (pid: 24329, threadinfo ffff88190f2b6000, task ffff881d217ac540)
    <0>[51178.495381] Stack:
    <4>[51178.495384]  0000000000000001 0000000000002db3 ffffffff81da1ac0 0000000000000000
    <4>[51178.495396]  00000000000720e1 ffffffffa014c29a 00000000000720e1 ffffffffa06cf1a0
    <4>[51178.495405]  00000000000720e1 ffffffff810001cb 00007fcc25041010 ffffffffa06cf1a0
    <0>[51178.495414] Call Trace:
    <4>[51178.495444]  [<ffffffffa014c29a>] newsendfile_init+0x29a/0x1000 [newsendfile]
    <4>[51178.495458]  [<ffffffff810001cb>] do_one_initcall+0x3b/0x180
    <4>[51178.495471]  [<ffffffff810a303f>] sys_init_module+0xcf/0x240
    <4>[51178.495482]  [<ffffffff8146f5f2>] system_call_fastpath+0x16/0x1b
    <4>[51178.495495]  [<00007fcc24c4ad7a>] 0x7fcc24c4ad79
    

      根据crash文件,我们获取以下对应函数的起始地址:

    objdump -D /home/caq/newsendfile.ko |grep replace_sendfile |head -10
    0000000000000050 <replace_sendfile>:
          64:       e8 00 00 00 00          callq  69 <replace_sendfile+0x19>
          70:       e8 00 00 00 00          callq  75 <replace_sendfile+0x25>
          7c:       48 89 05 00 00 00 00    mov    %rax,0x0(%rip)        # 83 <replace_sendfile+0x33>
          83:       e8 00 00 00 00          callq  88 <replace_sendfile+0x38>
          8f:       48 89 05 00 00 00 00    mov    %rax,0x0(%rip)        # 96 <replace_sendfile+0x46>
          96:       e8 00 00 00 00          callq  9b <replace_sendfile+0x4b>
          a2:       48 89 05 00 00 00 00    mov    %rax,0x0(%rip)        # a9 <replace_sendfile+0x59>
          a9:       e8 00 00 00 00          callq  ae <replace_sendfile+0x5e>
          b5:       48 89 05 00 00 00 00    mov    %rax,0x0(%rip)        # bc <replace_sendfile+0x6c>
    

      (0x50+0x2c2)=0x312,

    addr2line -e /home/caq/newsendfile.ko 0x312
    /home/caq/newsendfile.c:3007
    3001         p_xfs_file_operations                 =(struct file_operations*)kallsyms_lookup_name("xfs_file_operations");
    3002         pte_xfs_splice = lookup_address((unsigned long)p_xfs_file_operations, &level);
    3003         // change PTE to allow writing
    3004         //set_pte_atomic(pte_xfs_splice, pte_mkwrite(*pte_xfs_splice));
    3005
    3006     orig_xfs_file_splice_read = p_xfs_file_operations->splice_read;
    3007     p_xfs_file_operations->splice_read = caq_xfs_file_splice_read;

    而对应的行号3007的就是:   p_xfs_file_operations->splice_read = caq_xfs_file_splice_read;没有写权限的时候,去写这个page,就出crash了。可以明显看到,3006行是去读这个page,没事。

    水平有限,如果有错误,请帮忙提醒我。如果您觉得本文对您有帮助,可以点击下面的 推荐 支持一下我。版权所有,需要转发请带上本文源地址,博客一直在更新,欢迎 关注 。
  • 相关阅读:
    网页中的默认按钮
    心动不如行动
    周日骑行广州大学城
    买单车别买重车
    今晚好无聊
    在自行车论坛看到的有趣帖子
    php zend framework 生成 pdf 出现中文乱码
    FPDI Import existing PDF documents into FPDF
    PHP 哈希表,关联数组,遍历方法大全
    zend framework 如何多表查询
  • 原文地址:https://www.cnblogs.com/10087622blog/p/9338090.html
Copyright © 2011-2022 走看看