当前位置:   article > 正文

系统调用SYSCALL_DEFINE详解(Linux-4.x)_syscall_define4

syscall_define4

SYSCALL_DEFINE定义

 #define SYSCALL_DEFINE0(sname)                  \
     SYSCALL_METADATA(_##sname, 0);              \
     asmlinkage long sys_##sname(void)

 #define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
 #define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
 #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
 #define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
 #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
 #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
#define SYSCALL_DEFINEx(x, sname, ...)              \
    SYSCALL_METADATA(sname, x, __VA_ARGS__)         \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)

  • 1
  • 2
  • 3
  • 4

SYSCALL_METADATA宏定义是跟ftrace相关的一些调试数据结构定义,暂时可以不用管,实际上上面的宏定义等效于:

#define SYSCALL_DEFINEx(x, sname, ...)              \
    __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
  • 1
  • 2

最后最关键的来到了这里:

#define __SYSCALL_DEFINEx(x, name, ...)                 \
    asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))   \
        __attribute__((alias(__stringify(SyS##name))));     \
    static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));  \
    asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));  \
    asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))   \
    {                               \
        long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__));  \
        __MAP(x,__SC_TEST,__VA_ARGS__);             \
        __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));   \
        return ret;                     \
    }                               \
    static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

通过对__MAP和__SC_DECL进行解析,可知x表示的是该函数包含有x个参数。__VA_ARGS__中的每一对组成一个参数,分别表示参数类型和变量。

#define __MAP0(m,...)
#define __MAP1(m,t,a) m(t,a)
#define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__)
#define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__)
#define __MAP4(m,t,a,...) m(t,a), __MAP3(m,__VA_ARGS__)
#define __MAP5(m,t,a,...) m(t,a), __MAP4(m,__VA_ARGS__)
#define __MAP6(m,t,a,...) m(t,a), __MAP5(m,__VA_ARGS__)
#define __MAP(n,...) __MAP##n(__VA_ARGS__)

#define __SC_DECL(t, a) t a
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这里实际上实现了三个函数,分别是:

sys##name  //__attribute__((alias(__stringify(SyS##name))));指定为SyS##name的一个别名,所以两个函数是一样的
SyS##name
SYSC##name
  • 1
  • 2
  • 3

到这里可能会有一个疑问,正常的情况只需要定义一个函数sys##name不就行了吗?为什么搞那么复杂,中间还封装多余的两个函数呢?实际上这和内核之前的一个漏洞有关(CVE-2009-0029),后面才变为这种处理方式的。
这三个函数最大的差异就是就是传入的参数不同,利用__SC_CAST和__SC_LONG这两个宏,中间做了一次转换操作,把不同类型的参数先转换为long类型,然后又转换回来。

#define __SC_LONG(t, a) __typeof(__builtin_choose_expr(__TYPE_IS_LL(t), 0LL, 0L)) a
#define __SC_CAST(t, a) (t) a
  • 1
  • 2

CVE-2009-0029漏洞

在2.6.28和之前版本的内核中,对于一些64 bit平台的设备,要求在进行系统调用时由开发人员自行扩展对应的参数,也就是说64位的寄存器需要传入64位的参数,如果传入了32 bit的int型就可能出现异常或者崩溃,如果有人忽视了这个处理,就会很容易出漏洞。新的内核定义中进行了一些类型转换过程,从而避免这种由开发人员忽视可能产生的问题。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/214592
推荐阅读
  

闽ICP备14008679号