linux栈溢出检测原理,操作系统栈溢出检测之ucosII篇
Author : David Lin 林鹏
OS : 源码级理解掌握UcosRt-thread等嵌入式操作系统内核的设计与实现目前在研究linux内核路漫漫其修远兮吾将上下而求索 :)
转载请注明出处谢谢
前言
在嵌入式操作系统运行中进程的栈溢出问题是大家比较关心的问题由于资源限制栈大小受到限制本文主要介绍uc/os自带的栈检测机制为什么是
ucos而不是ecos或者其他因为我现在项目用这个后续有时间再介绍一种更简单通用不依赖具体操作系统的栈溢出检测机制。
原理
1.在进程的栈初始化的时候按预设的字节对齐方式用特定魔数比如0x9527ucosII预设是0值将栈元素依次完成初始化
2.在系统运行的时候通过守护进程依次遍历各个进程的栈检测栈元素的值是否等于初始化的魔数求得被污染的元素个数所占栈大小的比例即为栈使用量。
3.不通过守护进程直接对进程进行栈溢出检测是否可行可以不过不推荐在进程内部或者进程调度的时候进行如此使用量检测即使使用二分查找算法进行优化如果栈大到一定程度效 率问题还是需要慎重考虑的
4.不扯为什么这么设计这些事情了这跟小学语文写作者的中心思想一样不是ucos原作者所以不写你想知道Jean J. Labrosse怎么想的可以给他发邮件:-)
系统版本uc/osII V2.85
开发环境IAR for ARM (为什么不在linux下开发我也想知道
因为我喜欢gnu/linux,喜欢用gcc,gdb,vim,make,(⊙o⊙)…不过你懂的:-)1. 相关宏定义os_cfg.h
#defineOS_TASK_STAT_EN 1 /* Enable (1) or Disable(0) the statistics task*/
#defineOS_TASK_STAT_STK_CHK_EN 1 /* Check task stacks from statistic task */
2. 相关函数os_core.c os_task.c
static void OS_InitTaskStat (void) {……}; //初始化栈守护进程看哪个进程最贪吃 :-)
/*
*********************************************************************************************************
* INITIALIZATION
* CREATING THE STATISTIC TASK
*
* Description: This function creates the Statistic Task.
*
* Arguments : none
*
* Returns : none
*********************************************************************************************************
*/
#if OS_TASK_STAT_EN > 0
static void OS_InitTaskStat (void)
{
#if OS_TASK_NAME_SIZE > 7
INT8U err;
#endif
#if OS_TASK_CREATE_EXT_EN > 0
#if OS_STK_GROWTH == 1
(void)OSTaskCreateExt(OS_TaskStat,
(void *)0, /* No args passed to OS_TaskStat()*/
&OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1], /* Set Top-Of-Stack */
OS_TASK_STAT_PRIO, /* One higher than the idle task */
OS_TASK_STAT_ID,
&OSTaskStatStk[0], /* Set Bottom-Of-Stack */
OS_TASK_STAT_STK_SIZE,
(void *)0, /* No TCB extension */
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear */
#else
(void)OSTaskCreateExt(OS_TaskStat,
(void *)0, /* No args passed to OS_TaskStat()*/
&OSTaskStatStk[0], /* Set Top-Of-Stack */
OS_TASK_STAT_PRIO, /* One higher than the idle task */
OS_TASK_STAT_ID,
&OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1], /* Set Bottom-Of-Stack */
OS_TASK_STAT_STK_SIZE,
(void *)0, /* No TCB extension */
OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR); /* Enable stack checking + clear */
#endif
#else
#if OS_STK_GROWTH == 1
(void)OSTaskCreate(OS_TaskStat,
(void *)0, /* No args passed to OS_TaskStat()*/
&OSTaskStatStk[OS_TASK_STAT_STK_SIZE - 1], /* Set Top-Of-Stack */
OS_TASK_STAT_PRIO); /* One higher than the idle task */
#else
(void)OSTaskCreate(OS_TaskStat,
(void *)0, /* No args passed to OS_TaskStat()*/
&OSTaskStatStk[0], /* Set Top-Of-Stack */
OS_TASK_STAT_PRIO); /* One higher than the idle task */
#endif
#endif
#if OS_TASK_NAME_SIZE > 14
OSTaskNameSet(OS_TASK_STAT_PRIO, (INT8U *)"uC/OS-II Stat", &err);
#else
#if OS_TASK_NAME_SIZE > 7
OSTaskNameSet(OS_TASK_STAT_PRIO, (INT8U *)"OS-Stat", &err);
#endif
#endif
}
#endif
#if OS_TASK_CREATE_EXT_EN > 0
void OS_TaskStkClr (OS_STK *pbos, INT32U size,INT16U opt) {……}; //用于栈初始化
#endif
/*
*********************************************************************************************************
* CLEAR TASK STACK
*
* Description: This function is used to clear the stack of a task (i.e. write all zeros)
*
* Arguments : pbos is a pointer to the task's bottom of stack. If the configuration constant
* OS_STK_GROWTH is set to 1, the stack is assumed to grow downward (i.e. from high
* memory to low memory). 'pbos' will thus point to the lowest (valid) memory
* location of the stack. If OS_STK_GROWTH is set to 0, 'pbos' will point to the
* highest memory location of the stack and the stack will grow with increasing
* memory locations. 'pbos' MUST point to a valid 'free' data item.
*
* size is the number of 'stack elements' to clear.
*
* opt contains additional information (or options) about the behavior of the task. The
* LOWER 8-bits are reserved by uC/OS-II while the upper 8 bits can be application
* specific. See OS_TASK_OPT_??? in uCOS-II.H.
*
* Returns : none
*********************************************************************************************************
*/
#if OS_TASK_CREATE_EXT_EN > 0
void OS_TaskStkClr (OS_STK *pbos, INT32U size, INT16U opt)
{
if ((opt & OS_TASK_OPT_STK_CHK) != 0x0000) { /* See if stack checking has been enabled */
if ((opt & OS_TASK_OPT_STK_CLR) != 0x0000) { /* See if stack needs to be cleared */
#if OS_STK_GROWTH == 1
while (size > 0) { /* Stack grows from HIGH to LOW memory */
size--;
*pbos++ = (OS_STK)0; /* Clear from bottom of stack and up! */
}
#else
while (size > 0) { /* Stack grows from LOW to HIGH memory */
size--;
*pbos-- = (OS_STK)0; /* Clear from bottom of stack and down */
}
#endif
}
}
}
#endif
#if OS_TASK_CREATE_EXT_EN > 0
INT8U OSTaskStkChk (INT8U prio, OS_STK_DATA *p_stk_data) {……};
//用于检测各个进程的栈使用率被守护进程OS_TaskStat(void *p_arg)调用
#endif
/*
*********************************************************************************************************
* STACK CHECKING
*
* Description: This function is called to check the amount of free memory left on the specified task's
* stack.
*
* Arguments : prio is the task priority
*
* p_stk_data is a pointer to a data structure of type OS_STK_DATA.
*
* Returns : OS_ERR_NONE upon success
* OS_ERR_PRIO_INVALID if the priority you specify is higher that the maximum allowed
* (i.e. > OS_LOWEST_PRIO) or, you have not specified OS_PRIO_SELF.
* OS_ERR_TASK_NOT_EXIST if the desired task has not been created or is assigned to a Mutex PIP
* OS_ERR_TASK_OPT if you did NOT specified OS_TASK_OPT_STK_CHK when the task was created
* OS_ERR_PDATA_NULL if 'p_stk_data' is a NULL pointer
*********************************************************************************************************
*/
#if OS_TASK_CREATE_EXT_EN > 0
INT8U OSTaskStkChk (INT8U prio, OS_STK_DATA *p_stk_data)
{
OS_TCB *ptcb;
OS_STK *pchk;
INT32U free;
INT32U size;
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
#if OS_ARG_CHK_EN > 0
if (prio > OS_LOWEST_PRIO) { /* Make sure task priority is valid */
if (prio != OS_PRIO_SELF) {
return (OS_ERR_PRIO_INVALID);
}
}
if (p_stk_data == (OS_STK_DATA *)0) { /* Validate 'p_stk_data' */
return (OS_ERR_PDATA_NULL);
}
#endif
p_stk_data->OSFree = 0; /* Assume failure, set to 0 size */
p_stk_data->OSUsed = 0;
OS_ENTER_CRITICAL();
if (prio == OS_PRIO_SELF) { /* See if check for SELF */
prio = OSTCBCur->OSTCBPrio;
}
ptcb = OSTCBPrioTbl[prio];
if (ptcb == (OS_TCB *)0) { /* Make sure task exist */
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_NOT_EXIST);
}
if (ptcb == OS_TCB_RESERVED) {
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_NOT_EXIST);
}
if ((ptcb->OSTCBOpt & OS_TASK_OPT_STK_CHK) == 0) { /* Make sure stack checking option is set */
OS_EXIT_CRITICAL();
return (OS_ERR_TASK_OPT);
}
free = 0;
size = ptcb->OSTCBStkSize;
pchk = ptcb->OSTCBStkBottom;
OS_EXIT_CRITICAL();
#if OS_STK_GROWTH == 1
while (*pchk++ == (OS_STK)0) { /* Compute the number of zero entries on the stk */
free++;
}
#else
while (*pchk-- == (OS_STK)0) {
free++;
}
#endif
p_stk_data->OSFree = free * sizeof(OS_STK); /* Compute number of free bytes on the stack */
p_stk_data->OSUsed = (size - free) * sizeof(OS_STK); /* Compute number of bytes used on the stack */
return (OS_ERR_NONE);
}
#endif
/*$PAGE*/
/*
/*
*********************************************************************************************************
* TASK STACK DATA
*********************************************************************************************************
*/
#if OS_TASK_CREATE_EXT_EN > 0
typedef struct os_stk_data {
INT32U OSFree; /* Number of free bytes on the stack */
INT32U OSUsed; /* Number of bytes used on the stack */
} OS_STK_DATA;
#endif
#if OS_TASK_STAT_EN > 0
void OS_TaskStat (void *p_arg) {……}; //这个就是守护进程
#endif
/*
*********************************************************************************************************
* STATISTICS TASK
*
* Description: This task is internal to uC/OS-II and is used to compute some statistics about the
* multitasking environment. Specifically, OS_TaskStat() computes the CPU usage.
* CPU usage is determined by:
*
* OSIdleCtr
* OSCPUUsage = 100 * (1 - ------------) (units are in %)
* OSIdleCtrMax
*
* Arguments : parg this pointer is not used at this time.
*
* Returns : none
*
* Notes : 1) This task runs at a priority level higher than the idle task. In fact, it runs at the
* next higher priority, OS_TASK_IDLE_PRIO-1.
* 2) You can disable this task by setting the configuration #define OS_TASK_STAT_EN to 0.
* 3) You MUST have at least a delay of 2/10 seconds to allow for the system to establish the
* maximum value for the idle counter.
*********************************************************************************************************
*/
#if OS_TASK_STAT_EN > 0
void OS_TaskStat (void *p_arg)
{
INT32U run;
INT32U max;
INT8S usage;
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
p_arg = p_arg; /* Prevent compiler warning for not using 'parg' */
while (OSStatRdy == OS_FALSE) {
OSTimeDly(2 * OS_TICKS_PER_SEC / 10); /* Wait until statistic task is ready */
}
max = OSIdleCtrMax / 100L;
for (;;) {
OS_ENTER_CRITICAL();
OSIdleCtrRun = OSIdleCtr; /* Obtain the of the idle counter for the past second */
run = OSIdleCtr;
OSIdleCtr = 0L; /* Reset the idle counter for the next second */
OS_EXIT_CRITICAL();
if (max > 0L) {
usage = (INT8S)(100L - run / max);
if (usage >= 0) { /* Make sure we don't have a negative percentage */
OSCPUUsage = usage;
} else {
OSCPUUsage = 0;
}
} else {
OSCPUUsage = 0;
max = OSIdleCtrMax / 100L;
}
OSTaskStatHook(); /* Invoke user definable hook */
#if (OS_TASK_STAT_STK_CHK_EN > 0) && (OS_TASK_CREATE_EXT_EN > 0)
OS_TaskStatStkChk(); /* Check the stacks for each task */
#endif
OSTimeDly(OS_TICKS_PER_SEC / 10); /* Accumulate OSIdleCtr for the next 1/10 second */
}
}
#endif
/*$PAGE*/
#if OS_TASK_STAT_EN > 0
void OSStatInit (void) {……}; //每个进程都得调用它
#endif
/*
*********************************************************************************************************
* STATISTICS INITIALIZATION
*
* Description: This function is called by your application to establish CPU usage by first determining
* how high a 32-bit counter would count to in 1 second if no other tasks were to execute
* during that time. CPU usage is then determined by a low priority task which keeps track
* of this 32-bit counter every second but this time, with other tasks running. CPU usage is
* determined by:
*
* OSIdleCtr
* CPU Usage (%) = 100 * (1 - ------------)
* OSIdleCtrMax
*
* Arguments : none
*
* Returns : none
*********************************************************************************************************
*/
#if OS_TASK_STAT_EN > 0
void OSStatInit (void)
{
#if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
OS_CPU_SR cpu_sr = 0;
#endif
OSTimeDly(2); /* Synchronize with clock tick */
OS_ENTER_CRITICAL();
OSIdleCtr = 0L; /* Clear idle counter */
OS_EXIT_CRITICAL();
OSTimeDly(OS_TICKS_PER_SEC / 10); /* Determine MAX. idle counter value for 1/10 second */
OS_ENTER_CRITICAL();
OSIdleCtrMax = OSIdleCtr; /* Store maximum idle counter count in 1/10 second */
OSStatRdy = OS_TRUE;
OS_EXIT_CRITICAL();
}
#endif
/*$PAGE*/
/*
3. 如何使用系统API
Task_42 (void *p_arg) {
error_t error;
OSStatInit(); //这里应该是CCTV所描述的最美好的天朝请放我在这里
while(1) {
switch(num) {
case 42:
printf(“42 is the answer to life, the universe, and everything\n”);
break;
......
default:
break;
}
}
}
4. 使用
注意进程控制块的数据结构
/*
*********************************************************************************************************
* TASK CONTROL BLOCK
*********************************************************************************************************
*/
typedef struct os_tcb {
OS_STK *OSTCBStkPtr; /* Pointer to current top of stack */
#if OS_TASK_CREATE_EXT_EN > 0
void *OSTCBExtPtr; /* Pointer to user definable data for TCB extension */
OS_STK *OSTCBStkBottom; /* Pointer to bottom of stack */
INT32U OSTCBStkSize; /* Size of task stack (in number of stack elements) */
INT16U OSTCBOpt; /* Task options as passed by OSTaskCreateExt() */
INT16U OSTCBId; /* Task ID (0..65535) */
#endif
struct os_tcb *OSTCBNext; /* Pointer to next TCB in the TCB list */
struct os_tcb *OSTCBPrev; /* Pointer to previous TCB in the TCB list */
#if OS_EVENT_EN|| (OS_FLAG_EN > 0)
OS_EVENT *OSTCBEventPtr; /* Pointer to event control block */
#endif
#if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
void *OSTCBMsg; /* Message received from OSMboxPost() or OSQPost() */
#endif
#if (OS_FLAG_EN > 0) && (OS_MAX_FLAGS > 0)
#if OS_TASK_DEL_EN > 0
OS_FLAG_NODE *OSTCBFlagNode; /* Pointer to event flag node */
#endif
OS_FLAGS OSTCBFlagsRdy; /* Event flags that made task ready to run */
#endif
INT16U OSTCBDly; /* Nbr ticks to delay task or, timeout waiting for event */
INT8U OSTCBStat; /* Task status */
INT8U OSTCBStatPend; /* Task PEND status */
INT8U OSTCBPrio; /* Task priority (0 == highest) */
INT8U OSTCBX; /* Bit position in group corresponding to task priority */
INT8U OSTCBY; /* Index into ready table corresponding to task priority */
#if OS_LOWEST_PRIO <= 63
INT8U OSTCBBitX; /* Bit mask to access bit position in ready table */
INT8U OSTCBBitY; /* Bit mask to access bit position in ready group */
#else
INT16U OSTCBBitX; /* Bit mask to access bit position in ready table */
INT16U OSTCBBitY; /* Bit mask to access bit position in ready group */
#endif
#if OS_TASK_DEL_EN > 0
INT8U OSTCBDelReq; /* Indicates whether a task needs to delete itself */
#endif
#if OS_TASK_PROFILE_EN > 0
INT32U OSTCBCtxSwCtr; /* Number of time the task was switched in */
INT32U OSTCBCyclesTot; /* Total number of clock cycles the task has been running */
INT32U OSTCBCyclesStart; /* Snapshot of cycle counter at start of task resumption */
OS_STK *OSTCBStkBase; /* Pointer to the beginning of the task stack *//* 这里是栈基址*/
INT32U OSTCBStkUsed; /* Number of bytes used from the stack *//* 这里是使用量*/
#endif
#if OS_TASK_NAME_SIZE > 1
INT8U OSTCBTaskName[OS_TASK_NAME_SIZE];
#endif
} OS_TCB;
例如如下两个进程的控制块
1.栈溢出的进程如图1所示
OSTCBStkSize = 100(100是假设的值实际值如图所示是256)(怎么解决,把该进程OSTCBStkSize设置为大于840/4比如256 OK)
OSTCBStkUsed = 840(注意这里单位是char型所以需要除4之后与OSTCBStkSize比较)
两者的单位都是INT32U型OSTCBStkUsed > OSTCBStkSize
OMG!!! StackOverFlow (Id of Mine in stackOverFlow is linpeng1577@gmail.com )
图1
2.栈正常的进程如图2所示
注意进程控制块
OSTCBStkSize = 512
OSTCBStkUsed = 136(136/4 = 34 < 512)
两者的单位都是INT32U型OSTCBStkUsed < OSTCBStkSize
OMG!!! StackOverFlow? NO! (Id of Mine in stackOverFlow is linpeng1577@gmail.com )
图2
转载请注明出处
谢谢
linux栈溢出检测原理,操作系统栈溢出检测之ucosII篇相关推荐
- SPI锡膏检查机的作用和检测原理
SPI锡膏检查机的作用和检测原理 SPI是英文Solder Paste Inspection的简称,行业内一般人直接称呼为SPI,SPI的作用和检测原理是什么?下面江西英特丽电子给大家介绍 SPI锡膏 ...
- viola jones人脸检测原理
viola jones人脸检测原理 Viola-jones人脸检测算法是一种基于滑动窗口的目标检测算法,但它却克服了滑动窗口检测带来的低效问题,可以用于实时人脸检测,主要归功于以下三点: 利用一种新的 ...
- linux系统调用的封装格式,ARM Linux系统调用的原理
ARM Linux系统调用的原理ARM Linux系统调用的原理 操作系统为在用户态运行的进程与硬件设备进行交互提供了一组接口.在应用程序和硬件之间设置一个额外层具有很多优点.首先,这使得编程更加容易 ...
- OpenCV_09 模版匹配和霍夫变换:霍夫线检测+霍夫圆检测
1 模板匹配 1.1 原理 所谓的模板匹配,就是在给定的图片中查找和模板最相似的区域,该算法的输入包括模板和图片,整个任务的思路就是按照滑窗的思路不断的移动模板图片,计算其与图像中对应区域的匹配度,最 ...
- Linux 快照 (snapshot) 原理与实践(二) 快照功能实践
文章目录 0. 概要 1. 准备演示数据 2. 创建 snapshot-origin 目标 3. 创建 snapshot 目标 4. 验证 COW 操作 4.1 第一次写数据 4.2 第二次写数据 5 ...
- Linux 快照 (snapshot) 原理与实践(一) 快照基本原理
文章目录 0. 背景 1. 如何理解快照(snapshot)? 2. 快照 (snapshot) 的原理 2.1 全量快照 1. 克隆 (Clone) 2. 镜像分离 (Split Mirror) 2 ...
- 未来函数在线检测_嵌入式实时操作系统任务栈溢出检测原理
任务栈溢出概述 任务栈溢出是缓冲区溢出的一种. 由于缓冲区溢出而使得有用的存储单元被改写,往往会引发不可预料的后果.程序在运行过程中,为了临时存取数据的需要,一般都要分配一些内存空间,通常称这些空间为 ...
- stm32 栈溢检测c语言,栈溢出检查机制
分享一种栈溢出检查机制(硬件),适用于所有cm3芯片,只需对现有工程作四步修改 分享一种栈溢出检查机制(硬件),适用于所有cm3芯片,只需对现有工程作四步修改 一.需求 1.造成主栈(MSP)溢出的原 ...
- linux跟踪内存检测原理,wooyun/Linux下基于内存分析的Rootkit检测方法.html at master · exitmsconfig/wooyun · GitHub...
Linux下基于内存分析的Rootkit检测方法 - 路人甲 原文地址:http://drops.wooyun.org/tips/4731 0x00 引言 某Linux服务器发现异常现象如下图,确定被 ...
最新文章
- Redis 从入门到起飞(上)
- java 读文件夹_java怎么读取读取文件夹下的所有文件夹和文件?
- 云炬随笔20171209
- 使用PYTHON统计项目代码行数
- Springboot注册Listener
- 那么您想做微服务吗? 请观看微服务以防万一
- OpenCL memory object 之 Global memory (1)
- 关闭windows垃圾服务
- php1.9,PHP1.9--数组
- Js 与 as 相互通信
- java 基础知识九 类与对象
- 2017 10 13
- 科普:为什么DOTA2和LOL没有全图挂
- 【图像边缘检测】基于matlab插值法亚像素边缘检测【含Matlab源码 306期】
- Python模拟鼠标点击与实时获取鼠标位置
- UVA(WA) 10815 安迪的第一个字典
- vSphere Client连接主机提示远程服务器响应时间过长
- linux根据端口限速,Linux 中限制网络带宽使用trickle或wondershaper
- 【译】用Java创建你的第一个区块链-part2:可交易
- java入门习题,3000米长的绳子,每天减一半,问多少天这个绳子会小于5米?不考虑小数。
热门文章
- 3.0.2-Reaper(track)多通道乐器输出设置
- Yolov8损失函数改进:Wasserstein Distance Loss,助力小目标涨点
- 寻迹小车(模拟电路版)的设计制作与调试
- 广州某皮具公司进销存管理系统需求分析
- iPhone, Android等设备上的Touch和Gesture
- 空间数据WKT与WKB格式介绍
- python psutil模块_Python-psutil模块
- ps制作开关按钮图标
- Exchange 2010垃圾邮件功能开启及白名单设置
- php soapclient 乱码,接上一篇,php的soapclient的问题