首页 > 其他分享 >SYACALL_DEFINE系统调用

SYACALL_DEFINE系统调用

时间:2022-10-04 16:35:07浏览次数:57  
标签:__ 调用 SYACALL int void send long SC DEFINE

Linux的系统调用在内核中的入口函数都是 sys_xxx ,但是我们在内核源码去搜索时,无法找到 sys_xxx 的函数定义,这是因为Linux的系统调用对应的函数全部都是由 SYSCALL_DEFINE 相关的宏来定义的。

send 系统调⽤使用了SYACALL_DEFINE4 宏定义,4 表示系统调用了4个参数,分别为fd,buff,len,flags。函数内部返回了sys_sendto函数,即send系统调用真正使用的是sendto系统调用。

//file: net/socket.c
SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, unsigned int, flags)
{
	return sys_sendto(fd, buff, len, flags, NULL, 0);
}

SYACALL_DEFINE4 使用了 SYSCALL_DEFINEx 宏定义,将参数数量作为一个新的参数。

  • ##表示将左右的符号拼接在一起。
  • __VA_ARGS__表示前面...里面的可变参数。
  • SYSCALL_METADATA 是调试时跟踪系统调用的,无需关注。
  • asmlinkage 表示将函数参数存放在局部栈中(x86常用),FASTCALL表示将函数参数存放在R0~R4通用寄存器中(arm常用)。通常是系统调用的函数需要加armlinkage。
//file: include/linux/syscalls.h
#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__)

//代码展开
SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, unsigned int, flags) ->
SYSCALL_DEFINEx(4, _send, int, fd, void __user *, buff, size_t, len, unsigned int, flags)

SYSCALL_DEFINEx 为主要的实现过程,包含三个函数,sys,SyS,SYSC。其中,sys为SyS的别名,SyS调用了SYSC,SYSC后面没有分号,其定义在调用时给出。因此,sys/SyS->SYSC,前面的封装并不是调用过程。

//file: include/linux/syscalls.h
#define __SYSCALL_DEFINEx(x, name, ...)					\
	asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));	\  // 声明sys_send()
	static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));	\  // 声明SYSC_send()
	asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))	\  // 定义SyS_send()
	{								\
		long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__));	\  // 调用SYSC_send()
		__MAP(x,__SC_TEST,__VA_ARGS__);				\
		__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));	\  
		return ret;						\
	}								\
	SYSCALL_ALIAS(sys##name, SyS##name);				\  // 设置sys_send是SyS_send的别名
	static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))      // 定义SYSC_send()

//代码展开
SYSCALL_DEFINEx(4, _send, int, fd, void __user *, buff, size_t, len, unsigned int, flags)  ->

asmlinkage long sys_send(__MAP(4, __SC_DECL, int, fd, void __user *, buff, size_t, len, unsigned int, flags)); 
static inline long SYSC_send(__MAP(4, __SC_DECL, int, fd, void __user *, buff, size_t, len, unsigned int, flags)); 
asmlinkage long SyS_send(__MAP(4, __SC_DECL, int, fd, void __user *, buff, size_t, len, unsigned int, flags)) 
{
	long ret = SYSC_send(__MAP(4,__SC_CAST,int, fd, void __user *, buff, size_t, len, unsigned int, flags));
	__MAP(4,__SC_TEST,int, fd, void __user *, buff, size_t, len, unsigned int, flags);				
	return ret;
}
SYSCALL_ALIAS(sys_send, SyS_send); 
static inline long SYSC_send(__MAP(4, __SC_DECL, int, fd, void __user *, buff, size_t, len, unsigned int, flags)) 

还有一些其他的宏定义,主要是用来对宏参数进行变换。

//file: include/linux/syscalls.h
#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
#define __TYPE_IS_LL(t) (__same_type((t)0, 0LL) || __same_type((t)0, 0ULL))
#define __SC_LONG(t, a) __typeof(__builtin_choose_expr(__TYPE_IS_LL(t), 0LL, 0L)) a
#define __SC_CAST(t, a)	(t) a
#define __SC_ARGS(t, a)	a
#define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long))

#ifdef CONFIG_FTRACE_SYSCALLS
#define __SC_STR_ADECL(t, a)	#a
#define __SC_STR_TDECL(t, a)	#t

//代码展开
__MAP(4, __SC_DECL, int, fd, void __user *, buff, size_t, len, unsigned int, flags)  ->
__MAP4(__SC_DECL, int, fd, void __user *, buff, size_t, len, unsigned int, flags)    ->
__SC_DECL(int, fd), __MAP3(__SC_DECL, void __user *, buff, size_t, len, unsigned int, flags)    ->
__SC_DECL(int, fd), __SC_DECL(void __user *, buff), __SC_DECL(size_t, len), __SC_DECL(unsigned int, flags)  ->
int fd, void __user * buff, size_t len, unsigned int flags

__MAP(4,__SC_CAST,int, fd, void __user *, buff, size_t, len, unsigned int, flags)  ->
(int)fd, (void __user *)buff, (size_t)len, (unsigned int)flags

__MAP(4,__SC_TEST,int, fd, void __user *, buff, size_t, len, unsigned int, flags)  ->
(void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(int) && sizeof(int) > sizeof(long));
(void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(void __user *) && sizeof(void __user *) > sizeof(long));
(void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(size_t) && sizeof(size_t) > sizeof(long));
(void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(unsigned int) && sizeof(unsigned int) > sizeof(long));

最终得到的代码如下。使用多次宏替换,是为了将系统调用的参数统一变为了使用long类型来接收,然后再强转为本来参数类型。这样做的目的是解决Linux的CVE-2009-0029漏洞,该漏洞的大概意思是说:在Linux 2.6.28及以前版本的内核中,IBM/S390、PowerPC、Sparc64以及MIPS 架构64位平台的ABI要求在系统调用时,用户空间程序将系统调用中32位的参数存放在64位的寄存器中要做到正确的符号扩展,但是用户空间程序却不能保证做到这点,这样就会可以通过向有漏洞的系统调用传送特制参数便可以导致系统崩溃或获得权限提升。

asmlinkage long sys_send(int fd, void __user * buff, size_t len, unsigned int flags); // 声明sys_send()
static inline long SYSC_send(int fd, void __user * buff, size_t len, unsigned int flags); // 声明SYSC_send()
asmlinkage long SyS_send(long fd, long buff, long len, long flags) // 定义SyS_send()
{    
    (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(int) && sizeof(int) > sizeof(long));
    (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(void __user *) && sizeof(void __user *) > sizeof(long));
    (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(size_t) && sizeof(size_t) > sizeof(long));
    (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(unsigned int) && sizeof(unsigned int) > sizeof(long));
     return (long) SYSC_send((int) family, (int) type, (int) protocol); // 调用SYSC_send()
}
SYSCALL_ALIAS(sys_send, SyS_send); // 设置sys_send是SyS_send的别名
static inline long SYSC_send(int fd, void __user * buff, size_t len, unsigned int flags) // 定义SYSC_send()

标签:__,调用,SYACALL,int,void,send,long,SC,DEFINE
From: https://www.cnblogs.com/jpdeng/p/16753970.html

相关文章

  • 函数的递归调用
    介绍:一个函数在函数体内又调用了本身,称之为递归调用例子:  ①当在函数main内调用test(4)时,执行判断if,由于4>2,执行test(n-1),此时n=4,则传值为test(3)②继续执行判断if......
  • Java方法(方法的调用,重载)
    方法调用:调用方法:对象名.方法名(实参列表)Java支持两种调用方法的方式,根据方法是否返回值来选择当方法返回一个值的时候,方法调用通常被当做一个值,例如intlarger......
  • 利用ldt_struct 与 modify_ldt 系统调用实现任意地址读写
    利用ldt_struct与modify_ldt系统调用实现任意地址读写ldt_struct与modify_ldt系统调用的介绍ldt_struct​​ldt​​​是​​局部段描述符表​​​,里面存放的是进程的段描......
  • Verilog——任务task的调用
    参考自以下链接处:http://t.csdn.cn/4ws4t下面直接看代码,代码中会有注意事项。`timescale1ns/10psmoduletraffic_lights;regclk;reg......
  • C# 调用Winrar.exe压缩文件
    1、封装///<summary>///调用Winrar.exe进行压缩文件///</summary>///<paramname="sourcePath">需要压缩文件路径</param>///......
  • 函数调用机制图解
      1). 每个函数都有一个自己的栈当调用/执行一个函数时,就会开辟一个独立的空间(栈)此处优先执行main栈当接触到test时会重新创建一个test栈,并且把6传递给test的n......
  • 源码角度了解Skywalking之AbstractClassEnhancePluginDefine插件增强定义
    源码角度了解Skywalking之AbstractClassEnhancePluginDefine插件增强定义AbstractClassEnhancePluginDefine是所有插件的抽象类,我们在分析Skywalking初始化流程的时候见到......
  • 源码角度了解Skywalking之ClassEnhancePluginDefine拦截构造方法和类实例方法
    源码角度了解Skywalking之ClassEnhancePluginDefine拦截构造方法和类实例方法上篇文章我们分析到ClassEnhancePluginDefine的拦截静态方法进行增强,而Skywalking初始化的时......
  • java---回顾方法的定义和调用
    方法的回顾和调用packagecom.oop.demo;​importjava.io.IOError;importjava.io.IOException;​//return代表方法结束,返回一个结果//下方就是一个类publicclassDemo01......
  • Static的静态常量访问与静态方法调用
    Static的静态常量访问与静态方法调用======================================================================Static的静态方法调用packagecom.tea.Demo07;​public......