栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

linux那些事之SYSCALL

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

linux那些事之SYSCALL

SYSCALL_DEFINEx

内核代码中常常在查看系统调用宏时常常会看到使用SYSCALL_DEFINEX一系列宏定义来定义内核针对系统调用接口的定义

该宏位于includelinuxsyscalls.h文件中,针对系统调用的参数不同,使用了一系列的宏进行方便定义:

#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__)

针对不同的参数个数,一般会使用不同的宏定义,例如open系统调用总共由三个参数,内核中针对open的系统调用为:

SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
	return ksys_open(filename, flags, mode);
}

上述几个宏定义,最终都是调用SYSCALL_DEFINEx,

 SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)

在该宏中x参数代表的是系统调用参数个数,name为系统调用名称,例如open,被_##name扩展为_open,__VA_ARGS__代表的是参数个数

__SYSCALL_DEFINEx宏定义稍微有点复杂,同样是位于syscall.h文件中:

#define __SYSCALL_DEFINEx(x, name, ...)					
	__diag_push();							
	__diag_ignore(GCC, 8, "-Wattribute-alias",			
		      "Type aliasing is used to sanitize syscall arguments");
	asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))	
		__attribute__((alias(__stringify(__se_sys##name))));	
	ALLOW_ERROR_INJECTION(sys##name, ERRNO);			
	static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));
	asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__));	
	asmlinkage long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))	
	{								
		long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));
		__MAP(x,__SC_TEST,__VA_ARGS__);				
		__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));	
		return ret;						
	}								
	__diag_pop();							
	static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))

该宏定义稍微有点复杂:

  • __diag_push,__diag_ignore,__diag_pop这一系列宏主要是针对GCC编译器用来控制编译告警,其修改来源于:https://patchwork.kernel.org/project/linux-kbuild/patch/CAK7LNASvCha27kU4ipn23uOpNuxkzJrNzWBwYcxN4n=3xtv8SA@mail.gmail.com/
  • smlinkage long sys##name:用于对系统函数进行声明,open被扩展为sys_open,同时__SC_DECL和__VA_ARGS__用于对系统调用参数进行处理
  • asmlinkage long __se_sys##name: 用于定义 __se_sys前缀为名称的函数,该函数主要作用是对系统调用进行了封装:
	long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));
		__MAP(x,__SC_TEST,__VA_ARGS__);				
		__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));	
		return ret;						
  • 其函数最终是调用__do_sys##name 函数,例如open 系统调用最终调用的是__do_sys_open
  • __do_sys##name 为最终的系统调用实现

系统调用为什么设计这么复杂,主要原因是bug CVE-2009-0029,CVE-2010-3301的存在: Linux 2.6.28及以前版本的内核中,将系统调用中32位参数传入64位的寄存器时无法作符号扩展,可能导致系统崩溃或提权漏洞。
内核开发者通过将系统调用的所有输入参数都先转化成long类型(64位),再强制转化到相应的类型来规避这个漏洞

参考资料

Linux CVE-2009-0029 漏洞解析_麦兜布达拉的博客-CSDN博客

Diagnostic Pragmas (Using the GNU Compiler Collection (GCC))
Anatomy of a system call, additional content [LWN.net]

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/964974.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号