信息安全系统设计与实现学习笔记9

一、知识点归纳以及自己最有收获的内容

1、知识点归纳

第6章 信号和信号处理

1、信号和中断
“中断”是从I/O设备或协处理设备发送到CPU的外部请求,它将CPU从正常执行转移到中断处理。与发送给CPU的中断请求一样,“信号”是发送给进程的请求,将进程从正常执行转移到中断处理。

  • 进程的概念
    一个”进程“(引号中)就是一系列活动。
    广义的”进程“包括:
(1)从事日常事物的人。
(2)在用户模式或内核模式下运行的Unix/Linux进程。
(3)执行机器指令的CPU。
  • 中断

(1)人员中断
中断可分为三类:

来自硬件的中断∶大楼着火,闹钟响了等。
来自其他人的中断∶电话响了,有人敲门等。
自己造成的中断∶切到手指,吃得太多等。

按照紧急程度,中断可分为以下几类∶

不可屏蔽(NMI)∶大楼着火!
可屏蔽∶有人敲门等。

人员的每个动作函数都是通过本能或经验实现的。由于人员中断的种类太多,所以不能在上表中全部列出,但是思路应该清晰。

(2)进程中断
这类中断是发送给进程的中断。当某进程正在执行时,可能会收到来自3个不同来源的中断:

来自硬件的中断:终端、间隔定时器的"Ctrl+C"组合键等。
来自其他进程的中断:kill(pid,SIG#)、death_of_child 等。
自己造成的中断∶除以0、无效地址等。

(3)硬件中断
这类中断是发送给处理器或CPU的信号。它们也有三个可能的来源:

来自硬件的中断:定时器、I/O设备等。
来自其他处理器的中断:FFP、DMA、多处理器系统中的其他 CPU。
自己造成的中断:除以0、保护错误、INT指令。

(4)进程的陷阱错误
进程可能会自己造成中断。这些中断是由被 CPU 识别为异常的错误引起的,例如除以0、无效地址、非法指令、越权等。当进程遇到异常时,它会陷入操作系统内核,将陷阱原因转换为信号编号,并将信号发送给自己。如果在用户模式下发生异常,则进程的默认操作是终止,并使用一个可选的内存转储进行调试。如果在内核模式下发生陷阱,原因一定是硬件错误,或者很可能是内核代码中的漏洞,在这种情况下,内核无法处理。

2、Unix/Linux中的信号处理

  • 信号类型
    Unix/Linux支持31种不同的信号,每种信号在signal.h文件中都有定义,每种信号都有一个符号名。
#define SIGHUP 
#define SIGINT 
#define SIGQUIT 
#define SIGILL 
#define SIGTRAP
#define SIGABRT 
#define SIGBUS 
#define SIGFPE 
#define SIGKILL 
#define SIGUSR1
#define SIGSEGV 
#define SIGUSR2
#define SIGPIPE 
#define SIGALRM  
#define SIGTERM
#define SIGSTKFLT 
#define SIGCHLD
#define SIGCONT
#define SIGSTOP
#define SIGTSTP
#define SIGTTIN
#define SIGTTOU
#define SIGURG
#define SIGXCPU 
#define SIGXFSZ
#define SIGVTALRM
#define SIGPROF 
#define SIGWINCH 
#define SIGIO 
#define SIGPWR
#define SIGSYS
  • 信号来源
    (1)来自硬件的中断信号
    在执行过程中,一些硬件中断被转换为信号发送给进程硬件信号。
    (2)来自异常的信号
    当用户模式下的进程遇到异常时,会陷入内核模式,生成一个信号,并发送给自己。
    (3)来自其他进程的信号
    进程可以使用kill(pid,sig)系统调用向pid标识的目标进程发送信号。

  • 安装信号捕捉函数
    进程可使用系统调用:

int r = signal(int signal_number,voide *handler);

进程可使用信号调用向pid标识的另一个进程发送信号

int r = kill(pid, signal_number);

sh命令使用kill系统调用

kill -s signal_number pid

3、信号处理步骤

(1)当某进程处于内核模式时,会检查信号并处理未完成的信号。
(2)重置用户安装的信号捕捉函数:用户安装的陷阱相关信号捕捉函数用于处理用户代码中的陷阱错误。
(3)信号和唤醒:在Unix/Linux内核中有两种SLEEP进程:深度休眠进程和浅度休眠进程。

二、实践内容与截图

实践1:
运行以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
#include <string.h>
jmp_buf env;
int count = 0;
void handler(int sig, siginfo_t *siginfo, void *context)
{
    printf("handler: sig=%d from PID=%d UID=%d count=%d\n",
           sig, siginfo->si_pid, siginfo->si_uid, ++count);
    if (count >= 4) // let it occur up to 4 times
        longjmp(env, 1234);
}
int BAD()
{
    int *ip = 0;
    printf("in BAD(): try to dereference NULL pointer\n");
    *ip = 123; // dereference a NULL pointer
    printf("should not see this line\n");
}
int main(int argc, char *argv[])
{
    int r;
    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_sigaction = &handler;
    act.sa_flags = SA_SIGINFO;
    sigaction(SIGSEGV, &act, NULL);
    if ((r = setjmp(env)) == 0)
        BAD();
    else
        printf("proc %d survived SEGMENTATION FAULT: r=%d\n", getpid(), r);

    printf("proc %d looping\n", getpid());
    while (1)
        ;
}

运行结果

posted @ 2022-10-25 21:10  无响应trance少年  阅读(42)  评论(0)    收藏  举报