子进程中调用system命令执行openssl后,程序退出了,原因是SIGCHLD信号的处理

Regresshion漏洞本质:glibc 2.39+与OpenSSH信号竞态原理及防御 Regresshion(CVE-2024-6387)并非传统远程代码执行漏洞,而是一种由用户态信号处理逻辑退化引发的条件型竞态缺陷。其核心在于OpenSSH特权分离机制与glibc 2.39+中__pthread_kill_internal优化之间的时序冲突,导致SIGALRM触发下子进程栈损坏与内存重用。该漏洞不依赖堆溢出或类型混淆,而是利用信号投递、线程创建与资源清理间的微秒级窗口,具备高隐蔽性与低可检测性。技术价值体现在对Linux系统安全模型的深层挑战——它揭示了C库演进与上层服务兼容性之间被长期忽 阅读详情

源代码:

void quit_proc(int t)
{
  kill(0,15);  exit(0);
}

int main_worker(int argc, char *argv[])
{
  
  ......
  
  //自定义信号处理函数
  signal(SIGCHLD, quit_proc);
  //子进程结束时, 父进程会收到这个信号然后父进程也退出 

  for (i=0; i<childcnt; i++) {
    procid = fork();
    if ( !procid ) {
      //子进程      

      ......
      
      system("openssl ...");  //程序执行到这里就退出了,下面的跟踪没有打印出来
      printf("openssl ok!\n");
      
    } else if ( procid > 0 )  {
      //
    } else { i--; sleep( 5 ); }
  }
  while (1) sleep(1);

  return 0;
}

后来研究了一下,发现是由于父进程中(父进程A),SIGCHLD信号的处理方式被继承到子进程中(子进程B),子进程中调用system,system又会fork一个子进程(子进程C),这样当system的子进程C执行完后,子进程B收到了SIGCHLD信号,于是执行了quit_proc函数一起退出了


由于本身对信号机制不太懂吧,导致这种低级错误,上网搜索了一下,原来是要在子进程中要恢复SIGCHLD信号的默认处理方式就可以了

修改后的源代码:

void quit_proc(int t)
{
  kill(0,15);  exit(0);
}

int main_worker(int argc, char *argv[])
{
  
  ......
  
  //自定义信号处理函数
  signal(SIGCHLD, quit_proc);
  //子进程结束时, 父进程会收到这个信号然后父进程也退出 

  for (i=0; i<childcnt; i++) {
    procid = fork();
    if ( !procid ) {
      //子进程      
      signal(SIGCHLD,SIG_DFL);  //子进程以默认的方式处理该信号(system外部命令时不退出)
      
      ......
      
      system("openssl ...");  //程序执行到这里就退出了,下面的跟踪没有打印出来
      printf("openssl ok!\n");
      
    } else if ( procid > 0 )  {
      //
    } else { i--; sleep( 5 ); }
  }
  while (1) sleep(1);

  return 0;
}


1、关于在system中获取子进程的返回值与SIGCHLD

在Linux我们一般写的是Server程序,所以,一般在main函数中,首先将进程转换为后台进程,即调用deamon,deamon的一般实现。


deamon的实现中会忽略下面的信号:
signal(SIGINT, SIG_IGN);    //当在终端上按下ctrl+c后,会产生SIGINT信号。
signal(SIGHUP, SIG_IGN);    //终端退出时,会给所有的进程发送SIGHUP信号。
signal(SIGQUIT, SIG_IGN);   //终端退出时,会给所有的进程发送SIGQUIT信号。
signal(SIGPIPE, SIG_IGN);   //往没有读进程的管道中进行写操作。
signal(SIGTTOU, SIG_IGN);   //后台进程写tty
signal(SIGTTIN, SIG_IGN);   //后台进程读tty


signal(SIGCHLD, SIG_IGN);   
/*
子进程先于父进程结束时,会给父进程发送SIGCHLD信号
如果
1、父进程没有忽略SGICHLD信号;
或者
2、父进程没有调用wait或waitpid函数。
那么子进程将僵死。
(
在2.6内核,只要父进程显式忽略了SIGCHLD信号,
那么子进程将不会僵死,那么system将得不到子进程的退出状态。
也就是说system函数的返回值并不是子进程退出时的状态。
而2.4内核,只要父进程没有调用wait系列函数,子进程就将僵死。
不论是否忽略了SIGCHLD信号。
)
*/


signal(SIGTERM, SIG_IGN);   
/*
当kill pid时,向进程发送SIGTERM信号。
SIGTERM信号的默认处理是进程退出。
SIGTERM是进程在有可能的情况下退出。
注意::
killall  -9    process_name
发送的SIGKILL信号,强制进程退出。
*/

如果,我们在我们的server中需要调用system来调用外部脚本或程序来执行某写工作。

例如:
在脚本中通过wget下载文件::

#!/bin/bash
FILENAME=$0
PATHNAME=$1
wget $FILENAME $PATHNAME
if [ $? -eq 0 ] ; then
  exit 0
else
  exit -1
fi

例如::
char  command[1024];
url=http://test/test.rar;
pathname="./data";
sprintf(command,"./download.sh  %s   %s",url,pathname);
int ret = system(command);
if( ret == 0)
{
  //成功
}
else
{
  //失败
}
注意::
其中ret用来接收子进程退出是的返回值。即exit的返回值。
但是由于在deamon中忽略了SIGCHLD信号,所以主进程将不再接收子进程的返回值。所以,ret的值不能正确反映子进程的退出状态。

正确的做法是::
signal(SIGCHLD,SIG_DFL);                //默认处理方式,是接收子进程的返回值。
system(command);
signal(SIGCHLD,SIG_IGN);

2、system相关问题::
system函数其实是调用fork,exec,waitpid来实现的。
1、fork一个进程;
2、在子进程中调用exec去执行新程序。
3、在父进程中调用waitpid去等待子进程结束。
如果在父进程已经signal(SIGCHLD,SIG_IGN);那么子进程结束时,子进程的返回值不能被waitpid接收。
这个是必须关注的问题。

下面我们来分析system的实现:
下面给出system函数及SIGCHLD信号处理分别在2.6及2.4内核下的区别。system函数源码的一个实现如下:
int system(const char * cmdstring)
{
  pid_t pid;
  int status;
  if(cmdstring == NULL)
  {
    return (1);
  }
  if((pid = fork())<0)
  {
    status = -1;
  }
  else if(pid == 0)
  {
    execl("/bin/sh", "sh", "-c", cmdstring, (char *)0);
    _exit(127);
  }
  else
  {
    while(waitpid(pid, &status, 0) < 0)
    {
      if(errno != EINTR)
      {
        status = -1;
        break;
      }
    }
  }
  return status;
}

2.6内核下当父进程未调用wait系列函数等待子进程结束且未显式地忽略SIGCHLD信号,则子进程将成为僵死进程;(如果显示忽略,则子进程不僵死)
而在2.4内核中只要父进程未调用wait系列函数,则子进程就会成为僵死进程,不管是否显式地忽略SIGCHLD信号。
因而在SIGCHLD信号被显式忽略的情况下,2.6内核子进程将直接退出并释放资源,等父进程调用waitpid时,发现对应的pid进程已不存在,因而返回-1错误,errno为10(No child processes);
而在2.4内核下子进程在父进程waitpid之前不会退出,因而waitpid能成功获取子进程状态。

给大模型一台电脑:操作系统级AI指令执行协议 在AI工程化落地中,大模型与物理世界交互面临延迟高、上下文断裂、权限受限等核心瓶颈。传统HTTP API抽象层正成为能力天花板,而基于操作系统原生机制的指令直执行范式,通过进程管理、命名空间隔离、Seccomp-BPF过滤等技术,实现了低延迟、可审计、高确定性的AI-Agent本地协同。该方案不依赖云端服务,支持POSIX兼容环境,适用于工业控制、边缘推理、硬件编程等需模型直连设备的场景,是具身智能与操作系统深度集成的关键实践路径。 阅读详情

相关推荐

.NET智能体Shell技能工程实践:隔离、编排与可观测性

Shell命令是智能体连接操作系统与物理设备的核心执行通道,其本质是轻量级、低延迟、高权限的系统调用接口。在边缘AI与工业Agent场景中,Shell不仅承担指令下发任务,更需满足资源可控、故障隔离、依赖调度和全链路可观测等工程要求。本文围绕.NET AgentFramework的Skill机制,深入解析基于命名空间/cgroups/Job Object的三层环境隔离方案,YAML驱动的DAG式命令编排DSL,以及eBPF、inotify、tcpdump、seccomp构成的四层黑盒透视体系。结合小龙虾自动

weixin_33806914的博客 455

VSCode编写C++使用system()函数导致异常退出 解决办法

问题描述: VSCode运行代码,默认是使用集成控制台的。 C++中调用的system()函数可能会导致程序异常退出。 例如: /** * 主菜单界面显示 */ short homeMenu() { short code = 0; system("cls"); cout << "------------------------"; cout << "通讯录管理系统"; cout << "---------------

weixin_50551652的博客 2326

Ubuntu 16.04下NATS服务的systemd安全部署与TLS深度配置

NATS是一种轻量级云原生消息系统,其无状态、低延迟特性依赖操作系统级可靠运行。在Ubuntu 16.04这一systemd全面落地但兼容性敏感的LTS版本中,单纯启动gnatsd二进制远不足以支撑生产需求——必须通过systemd实现进程生命周期管理、资源隔离与日志治理;而TLS配置更非开关式启用,需结合证书权限控制、cipher套件硬编码、双向认证映射等系统级约束。本文围绕systemd服务单元设计、TLS 1.2+安全加固、最小权限用户隔离三大技术支柱,提供可审计、抗重启、符合CIS基线的NATS部署

weixin_30263073的博客 345

opensslWIN10安装以及常见解决问题

Openssl安装步骤及方法: 第一步、安装环境: 操作系统:window10(64位)(这里的版本一定要一样) C++编译器:VS2010、 vc++6.0等都可以 ActivePer: http://www.activestate.com/activeperl/downloads/; openssl-1.0.1: http://www.openssl.org/source/ (...

Mc951862140的博客 3510

Void Linux深度解析:runit、xbps与musl如何重构系统确定性

Linux发行版的核心价值正从‘功能丰富’转向‘行为可预测’。初始化系统(如runit替代systemd)、包管理机制(xbps的显式依赖与构建哈希)和C标准库(musl libc的ABI稳定性)共同构成系统确定性的三大支柱。这类设计显著降低嵌入式设备启动抖动、提升安全审计可验证性、保障交叉编译环境100%可重现。尤其在边缘计算、工业控制与合规敏感场景中,确定性直接转化为启动延迟下降74%、内存占用压缩68%、OTA失败率降低至0.2%等量化收益。本文以Void Linux为典型范例,深入剖析其放弃syst

weixin_30561425的博客 397

Agentic 编码本质:MCP 协议驱动的自主执行闭环

Agentic 编码不是高级代码补全,而是大模型驱动的自主工程执行范式——其核心在于构建‘推理→工具调用→状态感知→再推理’的闭环。这一能力依赖三大支柱:具备长程规划能力的推理模型(如 Claude Code)、标准化的模型-工具通信协议(MCP)、以及可安全调度的本地化插件生态(如 playwright_mcp、time_server)。MCP 协议突破传统 API 调用局限,让模型像工程师一样打开终端、查日志、调接口、看反馈,真正实现跨系统、有状态、可回溯的自动化。它已在工业边缘计算、金融系统运维、分布

weixin_30632883的博客 359

iOS https证书配置闪退问题

iOS使用的https证书都是.cer格式的,以往服务端给我的证书都是.pem或.crt格式,我通过终端转换为.cer后直接就能用了,很顺利。后面查了才知道,原来iOS用的.cer证书内容还必须是data格式的。

devil_0311的博客 359

CentOS 6日志集中化实战:Logstash与Kibana稳定部署指南

日志集中化是现代运维的基础能力,其核心在于将分散的日志数据统一采集、处理、存储与可视化。实现该目标需依托ELK(Elasticsearch、Logstash、Kibana)技术栈,但版本兼容性、系统约束与资源适配构成关键挑战。尤其在老旧操作系统如CentOS 6上,glibc 2.12、Linux 2.6.32内核、无systemd环境及有限硬件资源,使得Logstash和Kibana的部署远非简单安装,而需深度耦合内核行为、JVM参数、文件系统挂载选项与SELinux策略。本文聚焦真实生产约束,详解如何在

weixin_30772105的博客 328

嵌入式Linux网络编程实战:从i.MX6ULL并发服务器到TCP粘包处理

网络编程是构建现代嵌入式物联网应用的核心技术之一,其基础在于理解Socket通信机制。其原理是通过系统调用在进程间建立网络连接,实现数据收发。这项技术的核心价值在于为资源受限的嵌入式设备提供了稳定、高效的网络通信能力,是智能网关、远程监控等应用场景的基石。在实际工程中,开发者常面临**并发连接管理**和**TCP粘包/拆包**两大挑战。前者关乎服务器能否同时服务多个客户端,通常可通过多进程、多线程或I/O多路复用(如select、poll、epoll)模型解决;后者源于TCP是面向字节流的协议,没有消息边界

weixin_34212762的博客 487

Docker容器化Node.js应用:从环境一致性到生产就绪

容器化是解决软件交付中‘环境不一致’问题的核心技术范式,其本质是将应用及其运行时依赖封装为可移植、可复现的镜像单元。基于Linux命名空间与cgroups的隔离原理,Docker实现了进程、网络、文件系统等维度的强边界控制,显著提升部署确定性与团队协作效率。在Node.js工程实践中,它直接消解了版本冲突、全局依赖污染、跨平台兼容性等高频痛点,技术价值体现在CI/CD加速、微服务治理简化与云原生架构演进支撑上。典型应用场景包括Express后端服务容器化、Bootstrap前端资源静态托管、多环境一键交付及

weixin_30587927的博客 557

告别网络卡顿!保姆级教程:用国内镜像源5分钟搞定ESP32开发环境(Arduino IDE)

本文提供了一份保姆级教程,教你如何利用国内镜像源在5分钟内快速搭建ESP32开发环境(Arduino IDE),告别网络卡顿问题。教程详细介绍了镜像源配置、开发板安装、测试程序烧录等步骤,并包含与巴法云对接的实战案例,帮助开发者高效完成物联网项目。

weixin_42536058的博客 589

C语言为何仍是操作系统内核开发的首选?内存管理与硬件交互的绝对优势

在计算机系统编程领域,内存管理和硬件交互是两大核心基础概念。内存管理涉及程序如何分配、使用和释放内存资源,直接关系到程序的性能和稳定性;硬件交互则决定了软件能否直接、高效地控制底层硬件设备。这些底层技术原理构成了操作系统、驱动程序和嵌入式系统等关键基础设施的基石,其技术价值在于实现对计算资源的极致控制和高效利用。在操作系统内核、嵌入式固件、高性能中间件等对性能、资源消耗和确定性要求极高的应用场景中,开发者需要一种能够提供直接内存访问、最小运行时开销和高效硬件抽象的语言。C语言凭借其指针操作、内存布局控制和贴

android_mylove的专栏 442

软考中级信息系统监理师(第二版)-第21章基础设施工程监理

由于网络信息技术的飞速发展,变化日新月异,网络设计不但要保证目前网络传输容量的要求,也要考虑今后网络的发展,满足当前以及今后相当一段时间内的网络需求,便于向新技术的升级和衔接,同时又需要保护原有的投资。通用布缆系统工程中,承建单位的竣工文档主要包括以下内容:承建合同,招标文件,投标文件,设计方案,工程实施组织设计方案,工程施工报告,隐蔽工程记录,变更记录,自测报告,信息点分布图(表),园区、楼宇、水平配线表,楼层平面图及无线设备点位图,无线设备信息表,竣工图纸等。多排安装时,列间距不应小于1200mm。

2301_78583973的博客 1400

Docker部署核心原理与工程实践指南

Docker 是实现环境一致性与应用可移植性的关键容器技术,其本质是基于 Linux 内核的命名空间(namespaces)、控制组(cgroups)和分层文件系统(overlayfs)构建的运行时隔离机制。通过镜像(Image)封装完整运行环境、容器(Container)提供轻量实例、网络(Network)定义服务通信契约、存储(Volume)保障数据持久化,Docker 将软件交付从‘依赖手工配置’升级为‘声明式环境契约’。它显著提升多环境协同效率,支撑微服务解耦、CI/CD 自动化及私有化交付等典型场

weixin_30667649的博客 333

潜行游戏设计:核心机制与关卡设计解析

潜行游戏作为动作游戏的重要分支,通过视觉遮蔽、声音传播和AI行为树等复杂系统,为玩家提供独特的策略体验。视觉隐蔽系统采用视野锥和光照值的双重判定,声学传播模型模拟距离衰减和材质穿透,而敌人AI行为树则包含巡逻、警戒和团队协作等状态节点。这些技术不仅提升了游戏的真实感和挑战性,还在《合金装备》《刺客信条》等经典作品中得到广泛应用。潜行游戏的关卡设计强调多路径拓扑结构和环境叙事元素,通过沙漏模型和动态难度调节,平衡自由度和开发成本。未来,基于ML的适应性AI和物理模拟的隐蔽系统将成为创新方向。

weixin_42497762的博客 179

以 Joule 驱动的生成式开发:把需求文档直接变成可运行的 SAP 应用

摘要:SAP BTP的AI助手Joule正在改变开发方式,支持从自然语言描述自动生成数据模型、服务、UI及测试代码。在SAP Business Application Studio中,Joule能根据业务需求生成结构化代码,并提供代码补全、重构、解释等功能。开发者需注意避免上传敏感数据,并对AI生成的代码进行人工审核。Joule特别针对ABAP开发进行了优化,提供符合SAP规范的代码建议,帮助迁移遗留系统。此外,它还能快速生成CAP项目原型,但所有AI生成内容都需经过严格测试验证。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 340

闪退问题

记得注册

bug堆积处 1140

020、Sensor 供电设计:AVDD、DVDD、IOVDD 的上电时序与纹波要求

本文总结了图像传感器(Sensor)供电设计中的关键要点与常见问题:1. 三路供电特性差异:AVDD(模拟供电)对纹波最敏感(通常<30mVpp),DVDD需应对大电流瞬态变化,IOVDD需满足MIPI接口电压稳定要求。2. 上电时序至关重要,应遵循"模拟→数字→IO"的启动顺序,时序偏差可能导致初始化失败。3. 纹波控制需合理选择电容组合(如10μF+0.1μF),注意布局走线及电容ESR/ESL特性。4. 调试建议使用示波器多通道测量时序和纹波,重点关注传感器启动瞬间的电源特性。5. 经验教训包括预留设

sundong_81的博客 522

Openssl调用SSL_Shutdown过快有时导致程序退出

这是由于tcp另一端断开连接后,通信管道会中断(Broken pipe),如果仍然尝试读写操作,此时在一些linux下,系统会发出SIGPIPE信号(默认处理时退出程序),由于openssl也会检测这个错误,因此,我们只需要在程序的main函数出加上忽略此信号: signal(SIGPIPE, SIG_IGN); ...

iMatt的专栏 1342

C#操作MySQL从入门到精通(1)——安装MySQL数据库

我们使用C#操作MySQL数据库第一步要做的就是安装MySQL数据库,本文就是详细讲解如何安装MySQL数据库。

qq_34059233的博客 963

Claude Code 常见安装失败问题与解决办法

摘要: Claude Code安装失败通常与环境、网络和权限问题有关,而非软件本身。主要误区包括:命令未识别(需检查PATH和终端重启)、网络连接失败(终端代理配置)、权限不足(系统安全限制)及账号认证问题。首次使用应避免复杂任务,建议从基础功能测试开始。快速自检可按终端重启→命令识别→网络→代理→权限→账号状态的顺序排查。理顺终端、网络和权限后,Claude Code运行将更稳定。 (150字)

sg_knight的专栏 6692

system函数的总结

最近在看APUE第10章中关于system函数的

astrotycoon 7829

STM32芯片解锁读写保护:更改Option Byte [Error已解决]

解锁读保护:STLink更改Option Byte 变Level从1变为0,点击Apply即可。(程序执行读保护,其实是将Level从0变为1) 默认情况下该保护功能是不开启的,若要开启该功能,需要改写内部FLASH选项字节(Option Bytes)中的配置。 RDP读保护级别 级别0,无保护, 级别1,使能读保护, 这种保护下,若使用调试功能(使用下载器、仿真器)或者从内部SRAM自举时都不能对内部FLASH及备份SRAM作任何访问(读写、擦除都被禁止); 当芯片处于级别1的时候,可以把选项字节

HowieXue 薛永浩的博客 2万+

linux 主进程 线程的区别,linux system()函数问题

大家好,1.我在主程序里面pthread_create(&id,NULL,(void*)cp_thread,NULL)创建了个线程cp_thread2.在cp_thread()函数中system("cp*/media/disk");3.然后又在一个地方使用了pthread_cancel(id);可是问题出来了,就是当执行pthread_cancel(id)时候创建的线程是退出了,...

weixin_35486751的博客 315

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

上一篇: “API design is like sex: Make one mistake and support it for the rest of your life.”
下一篇: RESTful 最佳实践
笑天居士
博客等级 码龄24年 292粉丝 136原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值