免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2923 | 回复: 2
打印 上一主题 下一主题

[硬件及驱动] linux x86_64下add a new syscall的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-09-22 17:03 |只看该作者 |倒序浏览
本帖最后由 noted2011 于 2013-09-22 17:14 编辑

在linux x86_64位下,新增一个系统调用,但无法进入新的系统调用(sys_cpu_clock和sys_wait_wakeup)。
系统调用号183和184,系统是保留的。
具体可以看arch/x86/include/asm/unistd_64.h

/* reserved for AFS */
#define __NR_afs_syscall                        183
__SYSCALL(__NR_afs_syscall, sys_ni_syscall)

/* reserved for tux */
#define __NR_tuxcall                                184
__SYSCALL(__NR_tuxcall, sys_ni_syscall)

麻烦大家帮忙答疑一下,谢谢!

具体代码如下:
kernel:

#include <linux/module.h>
#include <linux/version.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/string.h>

#include <linux/if_arp.h>
#include <linux/slab.h>
#include <net/sock.h>
#include <net/datalink.h>
#include <net/psnap.h>
#include <linux/atalk.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/types.h>
#include <linux/ctype.h>

#include <linux/signal.h>
#include <linux/pid.h>


#define __NR_wait_wakeup   183
#define __NR_get_cpu_clock 184


struct {
    unsigned short limit;
    unsigned long base;
} __attribute__((packed)) idtr;

#if 0
struct {
    unsigned int off1;
    unsigned int sel;
    unsigned char none, flags;
    unsigned int off2;
} __attribute__((packed)) idt;
#endif

struct {
    u16 offset_low;
    u16 segment;
    unsigned ist : 3, zero0 : 5, type : 5, dpl :2, p : 1;
    u16 offset_middle;
    u32 offset_high;
    u32 zero1;
} __attribute__ ((packed)) idt;


unsigned long* syscall_table;
unsigned long old_handler222;
unsigned long old_handler223;


/**
* clear WP bit of CR0, and return the original value
*/
unsigned long clear_and_return_cr0(void)
{
    unsigned long cr0 = 0;
    unsigned long ret;

    asm volatile ("movq %%cr0, %0"
              : "=a"(cr0)
              );
    ret = cr0;

    /* clear the 20 bit of CR0, a.k.a WP bit */
        cr0 &= ~0x10000LL;
    //cr0 &= 0xfffeffff;

    asm volatile ("movq %0, %%cr0"
              :
              : "a"(cr0)
              );
    return ret;
}

/** set CR0 with new value
*
* @val : new value to set in cr0
*/
void setback_cr0(unsigned long val)
{
    asm volatile ("movq %0, %%cr0"
              :
              : "a"(val)
              );
}



unsigned long get_sys_call_table(void)
{
        unsigned long sys_call_off;
        unsigned long sys_call_table;
        char* p;
        int i;
       

    asm("sidt %0":"=m"(idtr));
        printk("addr of idtr: %p\n", &idtr);

    memcpy((char*)&idt, (char*)(idtr.base)+16*0x80, sizeof(idt));
        //sys_call_off=((idt.off2<<32)|idt.off1);
        sys_call_off =  (((unsigned long)idt.offset_high) << 32) |
        (((idt.offset_middle << 16) | idt.offset_low) & 0x00000000ffffffff);
        printk("addr of idt 0x80: %p\n", (void *)sys_call_off);
       
    p=(char*)sys_call_off;
    for (i=0; i<100; i++)
    {
   
        if (p=='\xff' && p[i+1]=='\x14' && p[i+2]=='\xc5')
        {
                //sys_call_tableµØÖ·¾ÍÔÚ0xff 0x14 0x85Ö®ºó
           sys_call_table=*(unsigned long*)(p+i+3);
           return sys_call_table;
        }
    }
        return 0;
}

/**
* Return the first appearence of NEEDLE in HAYSTACK.  -- copied from PHRACK
* */
static void *memmem(const void *haystack, size_t haystack_len,
                        const void *needle, size_t needle_len)
{/*{{{*/
        const char *begin;
        const char *const last_possible
                = (const char *) haystack + haystack_len - needle_len;

        if (needle_len == 0)
                /* The first occurrence of the empty string is deemed to occur at
                   the beginning of the string.  */
                return (void *) haystack;

        /* Sanity check, otherwise the loop might search through the whole
           memory.        */
        if (__builtin_expect(haystack_len < needle_len, 0))
                return NULL;

        for (begin = (const char *) haystack; begin <= last_possible;
                 ++begin)
                if (begin[0] == ((const char *) needle)[0]
                        && !memcmp((const void *) &begin[1],
                                   (const void *) ((const char *) needle + 1),
                                   needle_len - 1))
                        return (void *) begin;

        return NULL;
}/*}}}*/


static unsigned long get_syscall_table_long(void)
{/*{{{*/
#define OFFSET_SYSCALL 150
        unsigned long syscall_long, retval;
        char sc_asm[OFFSET_SYSCALL];

        rdmsrl(MSR_LSTAR, syscall_long);
        printk("long mode: system_call is at %p\n", (void *)syscall_long);

        memcpy(sc_asm, (char *)syscall_long, OFFSET_SYSCALL);

        retval = (unsigned long) memmem(sc_asm, OFFSET_SYSCALL, "\xff\x14\xc5", 3);
        if ( retval != 0 ) {
                printk("long mode : sys_call_table is at %p\n",
                                (void *) (* (unsigned long *)(retval+3)) ) ;
                retval = (unsigned long) ( * (unsigned long *)(retval+3) );
        } else {
                printk("long mode : memmem found nothing, returning NULL \n";
                retval = 0;
        }

#undef OFFSET_SYSCALL
        return retval;
}/*}}}*/




asmlinkage long sys_cpu_clock(unsigned long long * out)
{
        printk("sys get cpu clock";
    return 0;
}

asmlinkage long sys_wait_wakeup(unsigned int a, unsigned int b)
{
        printk("sys_wait_wakeup.\n";

    return 0;
}

static int mymod_init(void)
{
        unsigned long temp = 0;
        unsigned long orig_cr0 = clear_and_return_cr0();

        //temp = get_sys_call_table();
        temp = get_syscall_table_long();
        syscall_table = &temp;
        printk("temp %lu, *syscall_table %p.\n", temp, syscall_table);

        old_handler223 = syscall_table[__NR_get_cpu_clock];
        old_handler222 = syscall_table[__NR_wait_wakeup];
         
        printk("old handle for %d is : %lu @%p\n", __NR_wait_wakeup,old_handler222,
                 &syscall_table[__NR_wait_wakeup]);

        printk("old handle for %d is : %lu @%p\n", __NR_get_cpu_clock,old_handler223,
                &syscall_table[__NR_get_cpu_clock]);

        syscall_table[__NR_get_cpu_clock] = (unsigned long)sys_cpu_clock;
        syscall_table[__NR_wait_wakeup] = (unsigned long)sys_wait_wakeup;
        printk("get_cpu_clock %lu, wait_wakeup %lu.\n", syscall_table[__NR_get_cpu_clock], syscall_table[__NR_wait_wakeup]);
        setback_cr0(orig_cr0);

        printk("AGE_FLAGS_CHECK_AT_FREE is %x\n",PAGE_FLAGS_CHECK_AT_FREE);
       
    return 0;
}

static void mymod_exit(void)
{
        unsigned long orig_cr0 = clear_and_return_cr0();
        syscall_table[__NR_get_cpu_clock] = (unsigned long)old_handler223;
        syscall_table[__NR_wait_wakeup] = (unsigned long)old_handler222;
        setback_cr0(orig_cr0);
}

module_init(mymod_init);
module_exit(mymod_exit);
MODULE_LICENSE("GPL";
MODULE_AUTHOR("hxrd@hxrd.com";
MODULE_DESCRIPTION("transfer CPLD/DSP Interrupt to OAM in userspace";

insmod syscall.ko,串口的打印
long mode: system_call is at ffffffff81002820
long mode : sys_call_table is at 24448948814001e0
temp 2613364628280836576, *syscall_table ffff880044283f10.
old handle for 183 is : 0 @ffff8800442844c8
old handle for 184 is : 0 @ffff8800442844d0
get_cpu_clock 18446744072099139639, wait_wakeup 18446744072099139617.
PAGE_FLAGS_CHECK_AT_FREE is 693ce1

用户态的代码 userspace:
#include <stdio.h>
#include <sys/syscall.h>
#include <unistd.h>

void test_syscall(void)
{
        pid_t tid;
        int ret = 0;
        tid = syscall(SYS_gettid);
        printf("tid %d.\n", tid);
        ret = syscall(183, 0, 0);
        printf("183 syscall ret %d.\n", ret);
        ret = syscall(184, 0, 0);
        printf("184 syscall ret %d.\n", ret);
}

int main(int argc, void *argv[])
{
        test_syscall();
}

用户态代码执行的结果:
./test_syscall
tid 14348.
183 syscall ret -1.
184 syscall ret -1.

论坛徽章:
6
金牛座
日期:2013-10-08 10:19:10技术图书徽章
日期:2013-10-14 16:24:09CU十二周年纪念徽章
日期:2013-10-24 15:41:34狮子座
日期:2013-11-24 19:26:19未羊
日期:2014-01-23 15:50:002015年亚洲杯之阿联酋
日期:2015-05-09 14:36:15
2 [报告]
发表于 2013-09-23 13:38 |只看该作者
回复 1# noted2011

strace跟踪一下你的应用层程序,估计是没有导出这个系统调用吧。

或者 cat /proc/kallsyms 看看是否有afs_syscall等系统调用

   

论坛徽章:
0
3 [报告]
发表于 2013-09-24 15:24 |只看该作者
本帖最后由 noted2011 于 2013-09-24 16:30 编辑

谢谢瀚海书香的答复。

通过下面命令查看sys_call_table,发现获取得到的sys_call_table高32位是错误的。
grep sys_call_table /boot/System.map
ffffffff814001e0 R sys_call_table
ffffffff81408d60 r ia32_sys_call_table

主要修改如下,见下面的代码,测试OK。

#include <linux/module.h>
#include <linux/version.h>
#include <linux/moduleparam.h>
#include <linux/sched.h>
#include <linux/string.h>

#include <linux/if_arp.h>
#include <linux/slab.h>
#include <net/sock.h>
#include <net/datalink.h>
#include <net/psnap.h>
#include <linux/atalk.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/types.h>
#include <linux/ctype.h>

#include <linux/signal.h>
#include <linux/pid.h>


#define __NR_wait_wakeup   183
#define __NR_get_cpu_clock 184


void **syscall_table;
unsigned long *old_handler222;
unsigned long *old_handler223;



/**
* clear WP bit of CR0, and return the original value
*/
unsigned long clear_and_return_cr0(void)
{
    unsigned long cr0 = 0;
    unsigned long ret;

    asm volatile ("movq %%cr0, %0"
              : "=a"(cr0)
              );
    ret = cr0;

    /* clear the 20 bit of CR0, a.k.a WP bit */
        cr0 &= ~0x10000LL;
    //cr0 &= 0xfffeffff;

    asm volatile ("movq %0, %%cr0"
              :
              : "a"(cr0)
              );
    return ret;
}

/** set CR0 with new value
*
* @val : new value to set in cr0
*/
void setback_cr0(unsigned long val)
{
    asm volatile ("movq %0, %%cr0"
              :
              : "a"(val)
              );
}


/**
* Return the first appearence of NEEDLE in HAYSTACK.  -- copied from PHRACK
* */
static void *memmem(const void *haystack, size_t haystack_len,
                        const void *needle, size_t needle_len)
{/*{{{*/
        const char *begin;
        const char *const last_possible
                = (const char *) haystack + haystack_len - needle_len;

        if (needle_len == 0)
                /* The first occurrence of the empty string is deemed to occur at
                   the beginning of the string.  */
                return (void *) haystack;

        /* Sanity check, otherwise the loop might search through the whole
           memory.        */
        if (__builtin_expect(haystack_len < needle_len, 0))
                return NULL;

        for (begin = (const char *) haystack; begin <= last_possible;
                 ++begin)
                if (begin[0] == ((const char *) needle)[0]
                        && !memcmp((const void *) &begin[1],
                                   (const void *) ((const char *) needle + 1),
                                   needle_len - 1))
                        return (void *) begin;

        return NULL;
}/*}}}*/


static unsigned long get_syscall_table_long(void)
{/*{{{*/
#define OFFSET_SYSCALL 150
        unsigned long syscall_long, retval;
        char sc_asm[OFFSET_SYSCALL];

        rdmsrl(MSR_LSTAR, syscall_long);
        printk("long mode: system_call is at %p\n", (void *)syscall_long);

        memcpy(sc_asm, (char *)syscall_long, OFFSET_SYSCALL);

        retval = (unsigned long) memmem(sc_asm, OFFSET_SYSCALL, "\xff\x14\xc5", 3);
        if ( retval != 0 ) {
                printk("long mode : sys_call_table is at %p\n",
                                (void *) (* (unsigned long *)(retval+3)) ) ;
                retval = (unsigned long) ( * (unsigned long *)(retval+3) );
                retval = retval | 0xffffffff00000000;
                printk("sys_call_table is at %lu\n", retval);

        } else {
                printk("long mode : memmem found nothing, returning NULL \n");
                retval = 0;
        }

#undef OFFSET_SYSCALL
        return retval;
}/*}}}*/




asmlinkage long sys_cpu_clock(unsigned long long * out)
{
    printk("sys get cpu clock");
    return 0;
}

asmlinkage long sys_wait_wakeup(unsigned int a, unsigned int b)
{
    printk("sys_wait_wakeup.\n");

    return 0;
}

static int mymod_init(void)
{      
        unsigned long orig_cr0 = clear_and_return_cr0();

        syscall_table = (void **)get_syscall_table_long();   
        printk("syscall_table %p.\n", syscall_table);

        old_handler223 = syscall_table[__NR_get_cpu_clock];
        old_handler222 = syscall_table[__NR_wait_wakeup];

         
        printk("old handle for %d is : %p @%p\n", __NR_wait_wakeup,old_handler222,
                 &syscall_table[__NR_wait_wakeup]);

        printk("old handle for %d is : %p @%p\n", __NR_get_cpu_clock,old_handler223,
                &syscall_table[__NR_get_cpu_clock]);

        syscall_table[__NR_get_cpu_clock] = sys_cpu_clock;
        syscall_table[__NR_wait_wakeup] = sys_wait_wakeup;

        printk("get_cpu_clock %p, wait_wakeup %p.\n", syscall_table[__NR_get_cpu_clock], syscall_table[__NR_wait_wakeup]);
        setback_cr0(orig_cr0);

        printk("AGE_FLAGS_CHECK_AT_FREE is %x\n",PAGE_FLAGS_CHECK_AT_FREE);
      
    return 0;
}

static void mymod_exit(void)
{
        unsigned long orig_cr0 = clear_and_return_cr0();
        syscall_table[__NR_get_cpu_clock] = old_handler223;
        syscall_table[__NR_wait_wakeup] = old_handler222;
        setback_cr0(orig_cr0);
}

module_init(mymod_init);
module_exit(mymod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hxrd@hxrd.com");
MODULE_DESCRIPTION("transfer CPLD/DSP Interrupt to OAM in userspace");




您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP