Linux:用户空间非法指针coredump简析

news2024/11/28 12:45:21

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. 背景

本文分析基于 ARM32 架构Linux-4.14 内核代码。

3. 问题分析

3.1 测试范例

void main(void)
{
	*(int *)0 = 8;
}

运行程序会 coredump 。

3.2 分析

3.2.1 ARM32 3级页表(PAE使能)

在这里插入图片描述
上图看起有点复杂,我们简化一下,Linux 下内存的访问的过程大概是这样的:

          MMU页表
虚拟地址 --------> 物理地址

3.2.2 生成 coredump

每当发生内存访问时,如果从虚拟地址到物理地址的转换路径中,不管是哪级页表没有就绪,ARM32系统都会产生缺页中断,因此我们分析的起点就是缺页中断的入口。先看看中断向量表:

@ arch/arm/kernel/entry-armv.S

vector_stub	dabt, ABT_MODE, 8
	.long	__dabt_usr			@  0  (USR_26 / USR_32)
	.long	__dabt_invalid			@  1  (FIQ_26 / FIQ_32)
	.long	__dabt_invalid			@  2  (IRQ_26 / IRQ_32)
	.long	__dabt_svc			@  3  (SVC_26 / SVC_32)
	.long	__dabt_invalid			@  4
	.long	__dabt_invalid			@  5
	.long	__dabt_invalid			@  6
	.long	__dabt_invalid			@  7
	.long	__dabt_invalid			@  8
	.long	__dabt_invalid			@  9
	.long	__dabt_invalid			@  a
	.long	__dabt_invalid			@  b
	.long	__dabt_invalid			@  c
	.long	__dabt_invalid			@  d
	.long	__dabt_invalid			@  e
	.long	__dabt_invalid			@  f
	.globl	vector_fiq

	/* 各个CPU模式下的中断向量表指针 */
	.section .vectors, "ax", %progbits
.L__vectors_start:
	W(b)	vector_rst
	W(b)	vector_und
	W(ldr)	pc, .L__vectors_start + 0x1000
	W(b)	vector_pabt
	W(b)	vector_dabt /* DataAbort模式的中断向量表指针 */
	W(b)	vector_addrexcptn
	W(b)	vector_irq
	W(b)	vector_fiq

/* 缺页(DataAbort)中断可产生于[SVC、用户]两种模式下 */
__dabt_usr: /* 用户模式缺页中断 */
	...
	dabt_helper // bl	CPU_DABORT_HANDLER -> bl v7_early_abort
	...

  .align	5
__dabt_svc: /* SVC模式缺页中断 */
	...
	dabt_helper // bl	CPU_DABORT_HANDLER  -> bl v7_early_abort
	...
@ arch/arm/mm/abort-ev7.S

.align	5
ENTRY(v7_early_abort)
	mrc	p15, 0, r1, c5, c0, 0		@ get FSR
	mrc	p15, 0, r0, c6, c0, 0		@ get FAR
	uaccess_disable ip			@ disable userspace access
	...
	b	do_DataAbort
ENDPROC(v7_early_abort)
/*
 * 以3级页表举例。
 * arch/arm/mm/fsr-3level.c 
 */
static struct fsr_info fsr_info[] = {
	...
	/* 缺页中断处理接口 */
	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 1 translation fault"	}, /* 1级页目录转换接口 */
	{ do_translation_fault,	SIGSEGV, SEGV_MAPERR,	"level 2 translation fault"	}, /* 2级页目录转换接口 */
	{ do_page_fault,	SIGSEGV, SEGV_MAPERR,	"level 3 translation fault"	}, /* 3级页表项转换接口 */
	...
};

/*
 * arch/arm/mm/fault.c 
 */
asmlinkage void __exception
do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
	const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
	struct siginfo info;

	/* 调用具体类型缺页中断的入口: do_translation_fault() 或 do_page_fault() */
	if (!inf->fn(addr, fsr & ~FSR_LNX_PF, regs))
		return;
	
	...
}

如果第 1,2 级别页表导致的缺页中断,会进入 do_translation_fault()

static int __kprobes
do_translation_fault(unsigned long addr, unsigned int fsr,
		     struct pt_regs *regs)
{
	if (addr < TASK_SIZE) /* 用户空间地址 */
		return do_page_fault(addr, fsr, regs);
	
	...
}

第3级页表导致的缺页中断,进入 do_page_fault() ,这和第1,2级页表导致缺页中断的情形殊途同归。来看 do_page_fault()

static int __kprobes
do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
	struct task_struct *tsk;
	...
	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;

	...
	tsk = current;
	...
	
	fault = __do_page_fault(mm, addr, fsr, flags, tsk);

	...
}
static int __kprobes
__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
		unsigned int flags, struct task_struct *tsk)
{
	/*
	 * 查看addr是否存在对应的 vma ? 
	 * 如果没有的话,意味着非法地址访问.
	 */
	vma = find_vma(mm, addr);
	fault = VM_FAULT_BADMAP;
	if (unlikely(!vma))
		goto out;
	
	...

out:
	return fault;
}

__do_page_fault() 返回 do_page_fault()

static int __kprobes
do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
	struct task_struct *tsk;
	...
	unsigned int flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE;

	...
	tsk = current;
	...
	
	fault = __do_page_fault(mm, addr, fsr, flags, tsk);

	...
	
	if (!(fault & VM_FAULT_ERROR) && flags & FAULT_FLAG_ALLOW_RETRY) {
		if (fault & VM_FAULT_MAJOR) {
			tsk->maj_flt++;
			...
		}  else {
			tsk->min_flt++;
			...
		}
		...
	}
	
	...

	if (fault & VM_FAULT_SIGBUS) {
		...
	} else { /* 测试代码场景走这里 */
		/*
		 * Something tried to access memory that
		 * isn't in our memory map..
		 */
		sig = SIGSEGV;
		code = fault == VM_FAULT_BADACCESS ?
			SEGV_ACCERR : SEGV_MAPERR;
	}
	
	__do_user_fault(tsk, addr, fsr, sig, code, regs);
	return 0;
	
	...
}
static void
__do_user_fault(struct task_struct *tsk, unsigned long addr,
		unsigned int fsr, unsigned int sig, int code,
		struct pt_regs *regs)
{
	struct siginfo si;

	...

#ifdef CONFIG_DEBUG_USER
	if (((user_debug & UDBG_SEGV) && (sig == SIGSEGV)) ||
	    ((user_debug & UDBG_BUS)  && (sig == SIGBUS))) {
		printk(KERN_DEBUG "%s: unhandled page fault (%d) at 0x%08lx, code 0x%03x\n",
		       tsk->comm, sig, addr, fsr);
		show_pte(tsk->mm, addr);
		show_regs(regs);
	}
#endif

	tsk->thread.address = addr;
	tsk->thread.error_code = fsr;
	tsk->thread.trap_no = 14;
	si.si_signo = sig;
	si.si_errno = 0;
	si.si_code = code;
	si.si_addr = (void __user *)addr;
	force_sig_info(sig, &si, tsk); /* 给出错进程发送 SIGSEGV 信号 */
}

出错进程处理 SIGSEGV 信号:

asmlinkage int
do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
{
	...
	do {
		if (likely(thread_flags & _TIF_NEED_RESCHED)) {
			...
		} else {
			if (unlikely(!user_mode(regs)))
				return 0;
			if (thread_flags & _TIF_SIGPENDING) {
				int restart = do_signal(regs, syscall); /* 信号处理 */
				...
			} else if (thread_flags & _TIF_UPROBE) {
				...
			} else {
				...
			}
		}
		...
	} while (thread_flags & _TIF_WORK_MASK);
	return 0;
}
static int do_signal(struct pt_regs *regs, int syscall)
{
	...
	if (get_signal(&ksig)) {
		...
	} else {
		...
	}
	return 0;
}
int get_signal(struct ksignal *ksig)
{
	...
	for (;;) {
		...
		signr = dequeue_synchronous_signal(&ksig->info);
		if (!signr)
			signr = dequeue_signal(current, &current->blocked, &ksig->info);

		if (!signr)
			break; /* will return 0 */
		
		...

		if (ka->sa.sa_handler != SIG_DFL) {
			/* Run the handler.  */
			ksig->ka = *ka;

			if (ka->sa.sa_flags & SA_ONESHOT)
				ka->sa.sa_handler = SIG_DFL;

			break; /* will return non-zero "signr" value */
		}
		
		...
	}
	
fatal:
	if (sig_kernel_coredump(signr)) {
			if (print_fatal_signals)
				print_fatal_signal(ksig->info.si_signo);
			...
			do_coredump(&ksig->info); /* 产生 coredump 文件 */
	}

	...
}

4. 调试 coredump 问题

产生的 coredump 文件,可用 gdb 进行调试 。

5. 后记

本文涉及到信号处理,更多信号处理细节可参考 Linux信号处理简析 。本文没有对程序的 coredump 细节进行展开,它有点复杂,留待后续有机会再进行述说。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/345101.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Seata-Server分布式事务原理加源码 (七) - TCC事务模式

TCC事务模式 首先我们先来了解常规的TCC模式。 什么是TCC TCC 是分布式事务中的二阶段提交协议&#xff0c;它的全称为 Try-Confirm-Cancel&#xff0c;即资源预留&#xff08;Try&#xff09;、确认操作&#xff08;Confirm&#xff09;、取消操作&#xff08;Cancel&#…

CV——day77 简读论文:视频中交通标志的跟踪检测

视频中交通标志的跟踪检测Detection-by-tracking of traffic signs in videos1 Introduction3 Methods3.1 Faster R-CNN3.2 Proposed shortest-path approach3.3 Tractor-based method3.4 IoU-based method6 ConclusionsDetection-by-tracking of traffic signs in videos 视频…

除了ChatGPT,还能用什么计划管理软件提高效率?

最近一段时间&#xff0c;人工智能工具ChatGPT成为互联网科技圈的热门话题。正如当年的阿尔法狗给世界带来的震动一样&#xff0c;人们讨论的最多的就是&#xff1a;ai智能会不会取代人工&#xff0c;因为ai的效率太高了&#xff0c;但再智能&#xff0c;也有ai永远也取代不了的…

ROS2机器人编程简述humble-第四章-IMPROVED DETECTOR .4

ROS2之TF2小练习-颜色随机器人和障碍物直接距离变化ROS2之TF2小练习-有哪些bug找找看里面给出了&#xff1a;ROS2机器人编程简述humble-第四章-BASIC DETECTOR .3需要改进哪些地方呢&#xff1f;检测之后&#xff0c;距离不变了……如何变化&#xff1f;这个问题可以问chatgpt吗…

【Linux】TCP并发网络编程

多线程网络编程 上一节我们讲到&#xff0c;当我们的多个客户端区连接同一个服务端的时候就会出现问题&#xff0c;这是因为一个返回值只能接收一个客户端传输的消息&#xff0c;那么我们想要多个客户端同时链接服务端&#xff0c;我们就要有这样一个思路&#xff0c;发过来一…

金三银四?铜三铁四才对吧......

往年的金三银四&#xff0c;今年被戏称为“铜三铁四”。知名的大厂HR们都在不断的裁员&#xff0c;能被保住不被裁掉可能就万事大吉了&#xff0c;赛道越来越窄&#xff0c;都在预测未来计算机行业是不是下一个土木工程&#xff1f; 我也算是软件测试岗位的老鸟了&#xff0c;…

2.6 尚品汇 day13 二级路由 饿了么ui 表单使用以及验证(不完整)、上线后的跨域代理(nginx)

二级路由 1.1路由结构 1.2 引入二级路由 1.2.2配置路由信息 1.3 声明导航 1.4配置路由出口 饿了么ui 表单使用以及验证 使用 1.1.1复制结构 1.1.2 在main.js 按需引入 引入首字母大写&#xff0c;-用大写替代&#xff0c;el省略&#xff0c;一定要引用完整 注意Vue.compon…

Smartbi观点 | ChatGPT还处于初级阶段?然而AI早已打入BI内部

最近&#xff0c;当我们还沉浸在电影《流浪地球2》MOSS所带来的震感时&#xff0c;ChatGPT又火爆社交媒体&#xff0c;成为全球“新顶流”。 官方数据显示&#xff0c;今年1月&#xff0c;平均每天约有1300万独立访客使用 ChatGPT&#xff0c;累计用户超1亿&#xff0c;创下了互…

Java 基础面试题——关键字

目录1.Java 中的关键字是指什么&#xff1f;有哪些关键字&#xff1f;2.instanceof 关键字的作用是什么&#xff1f;3.访问修饰符 public、private、protected、以及不写&#xff08;default&#xff09;时的区别&#xff1f;4.Java 中有没有 goto 关键字?5.在 Java 中&#x…

第一章SpringBoot简介

文章目录什么是SpringBoot了解我们的Spring能干什么Spring的生态为什么需要SpringBootSpringBoot优点SpringBoot缺点SpringBoot的大时代背景微服务分布式分布式的困难分布式的解决云原生上云的困难SpringBoot之Helloworld新添我们的maven相关的配置创建一个maven项目并导入依赖…

Seata-Server分布式事务原理加源码(二) - 分布式事务解决方案

分布式事务解决方案 2PC即两阶段提交协议&#xff0c;是将整个事务流程分为两个阶段&#xff0c;P是指准备阶段&#xff0c;C是指提交阶段。 准备阶段&#xff08;Prepare phase&#xff09;提交阶段&#xff08;commit phase&#xff09; 举例&#xff1a;比如说相亲对象两…

微服务项目【秒杀商品展示及商品秒杀】

登录方式调整 第1步&#xff1a;从zmall-common的pom.xml中移除spring-session-data-redis依赖 注意&#xff1a; 1&#xff09;本次不采用spring-session方式&#xff0c;改用redis直接存储用户登录信息&#xff0c;主要是为了方便之后的jmeter压测&#xff1b; 2&#xff09…

魔兽世界WOW私服架设详细教程

1. 写在前面&#xff1a;此教程是针对国服WOW3.3.5.13930版本的&#xff0c;因为目前魔兽单机在此版本下运行最正常。WOW4.0以上版本还有些许问题2. 准备文件&#xff08;1&#xff09;WOW3.3.5.13930客户端&#xff0c;没有的可以从这里下载WOW 3.3.2安装文件和WOW3.3.2-3.3.5…

【linux C】daemon函数应用之——进程守护小工具,运维仔看了都说好!并附带shell版本

最近接触到Linux C中的daemon函数&#xff0c;顾名思义&#xff0c;它和守护进程Daemon有关&#xff1b;简单来说Linux Daemon&#xff08;守护进程&#xff09;是运行在后台的一种特殊进程&#xff1b; 一般来说&#xff0c;它独立于控制终端并且周期性地执行某种任务或等待处…

认识V模型、W模型、H模型

软件测试与软件工程息息相关&#xff0c;软件测试是软件工程组成中不可或缺的一部分。 在软件工程、项目管理、质量管理得到规范化应用的企业&#xff0c;软件测试也会进行得比较顺利&#xff0c;软件测试发挥的价值也会更大。 要关注软件工程、质量管理以及配置管理与软件测试…

ChatGPT中文网尝鲜,感觉自己快下岗了

最近很火的ChatGPT之初体验 ChatGPT中文网 居然可以回答代码问题 尝试了一下, 它居然说自己是一个人 顺便问了下简单的java代码问题 “使用java语言写一个递归打印D盘中所有文件名的程序” 很流畅的回答了出来,注释还写得比我详细,感觉我离下岗不远了 这就是GPT写的代码 i…

工人不戴安全帽自动检测识别 opencv

工人不戴安全帽自动检测识别通过pythonopencv深度学习网络模型&#xff0c;工人不戴安全帽自动检测识别算法对现场人员穿戴进行全天候不间断识别检测&#xff0c;发现现场人员违规行为着装自动抓拍存档。Python是一门解释性脚本语言。解释性语言&#xff1a;解释型语言&#xf…

C语言中大小端问题

目录 一、什么是大小端 二、 举个例子 三、大小端演示 四、解释"二"中举例的问题 ​五、怎么判断是大端还是小端 六、一个题目 一、什么是大小端 大端模式&#xff08;大端字节序存储&#xff09;&#xff1a;就是高位字节数据存放在内存的低地址端&#xff…

工序排序问题--约翰逊法精讲

什么是约翰逊法?约翰逊法是作业排序中的一种排序方法。选出最短加工时间i*&#xff0c;若最短加工时间有多个&#xff0c;任选1个.若i*出现在机床1&#xff0c;它对应的工件先安排加工&#xff0c;否则放在最后安排&#xff0c;安排后划去该工件,重复上两个步骤&#xff0c;直…

python3.11下载安装详细教程

python3.11新的功能特性 1. 支持新的字符串格式化功能&#xff0c;允许使用更多的格式化选项&#xff1b; 2. 支持新的数据类型&#xff0c;如结构化数据类型&#xff1b; 3. 支持新的编程模型&#xff0c;如asyncio&#xff1b; 4. 支持新的编程语言特性&#xff0c;如f-s…