CVE-2024-55030:NASA fPrime 队列溢出导致 DoS 漏洞

CVE-2024-55030:NASA fPrime 队列溢出导致 DoS 漏洞

Ots安全 2025-05-15 07:30

网址

Remote Code Execution and Critical Vulnerabilities in NASA fprime v3.4.3

目标
– fPrime≤v3.4.3

解释

fPrime 是一个用于航天应用和嵌入式系统的轻量级开发和部署软件框架。系统由通过通信端口连接的组件组成,组件之间的通信通过事件和命令进行。组件提供输入/输出端口来联系(或与其他元素通信),通知它们事件或发送和接收命令。

命令调度服务也是 fprime 框架内的一个组件,它从外部接收命令并将其传递到内部组件。此时,传输到指挥调度服务的外部命令是从地面系统传输的,如下图所示。地面系统负责与配备飞行软件的外部系统(例如卫星)进行通信和控制。

根本原因

当命令调度服务处理大量来自外部的命令时,就会出现内部命令队列(
m_queue或
m_seqCmdBuffQueue)溢出的问题。该服务从外部源(例如地面系统)接收命令并将其转发到目标组件进行处理。

pipeline/standard.py通过将函数修改
send_command为无限循环 [1](该循环快速地重复发送命令),可以重现该问题。当短时间内出现异常大量的命令时,命令调度服务将不堪重负地使用其内部队列来处理这些命令。

def send_command(self, command, args):
    """Sends commands to the encoder and history.

    :param command: command id from dictionary togetcommand template
    :param args: arguments to process
    """
    if isinstance(command, str):
        command_template = self.dictionaries.command_name[command]
    else:
        command_template = self.dictionaries.command_id[command]
    cmd_data = fprime_gds.common.data_types.cmd_data.CmdData(
        tuple(args), command_template
    )
    cmd_data.time = fprime.common.models.serialize.time_type.TimeType()
    cmd_data.time.set_datetime(datetime.datetime.now(), 2)
    while1: // [1] Infinite Loop
          self.coders.send_command(cmd_data)

根本原因在于将接收到的命令放入内部队列的逻辑。以下代码用于
CommandDispatcherComponentBase::seqCmdBuff_handlerBase()对函数中接收到的命令消息()进行排队:
msg

Os::Queue::QueueBlocking _block = Os::Queue::QUEUE_NONBLOCKING; // [2]
Os::Queue::QueueStatus qStatus = this->m_queue.send(msg, 0, _block); // 메시지를 큐에 전송 시도

FW_ASSERT(
    qStatus == Os::Queue::QUEUE_OK, 
    static_cast<FwAssertArgType>(qStatus) 
);

这段代码中,队列传输模式
Os::Queue::QUEUE_NONBLOCKING设置为[2],即当队列满的时候,立即返回状态,不会阻塞。在内部,
this->m_queue.send()它
bareSendNonBlock()调用[3],

Queue::QueueStatus Queue::send(const Fw::SerializeBufferBase &buffer, NATIVE_INT_TYPE priority, QueueBlocking block) {
    const U8* msgBuff = buffer.getBuffAddr();
    NATIVE_INT_TYPE buffLength = buffer.getBuffLength();

    return this->send(msgBuff, buffLength, priority, block);
}

Queue::QueueStatus Queue::send(const U8* buffer, NATIVE_INT_TYPE size, NATIVE_INT_TYPE priority, QueueBlocking block) {
    //Check if the handle is null or check the underlying queue is null

        /* ... */
        
    //Send to the queue
    if (QUEUE_NONBLOCKING == block) { //[3]
        return bareSendNonBlock(handle, buffer, size, priority);
    }

    return bareSendBlock(handle, buffer, size, priority);
}

这再次
push()尝试通过调用实际缓冲区队列实现的方法将数据插入队列[4]。

Queue::QueueStatus bareSendNonBlock(BareQueueHandle& handle, const U8* buffer, NATIVE_INT_TYPE size, NATIVE_INT_TYPE priority){

    / * ... */
    
    Queue::QueueStatus status = Queue::QUEUE_OK; 
    bool success = queue.push(buffer, size, priority); // [4]
    if(!success) { // push가 실패했다면 (e.g., 큐가 가득 찼다면)
        status = Queue::QUEUE_FULL; // 상태를 QUEUE_FULL로 설정
    }
    return status; // 최종 상태 반환
}

如果队列已满,push()则返回false,
bareSendNonBlock()通过函数
Os::Queue::QUEUE_FULL转换为状态(错误代码8)并存储在[5]m_queue.send()的返回值中。qStatus

问题FW_ASSERT出现在下一行语法中。这个断言qStatus断言。
Os::Queue::QUEUE_OK但是,如果队列溢出到(8),则此断言条件变为假,并且断言失败。
qStatusOs::Queue::QUEUE_FULL

Os::Queue::QueueBlocking _block = Os::Queue::QUEUE_NONBLOCKING; 
Os::Queue::QueueStatus qStatus = this->m_queue.send(msg, 0, _block); 

FW_ASSERT( // 전송 상태에 대한 어설션 체크
    qStatus == Os::Queue::QUEUE_OK, // [5] 상태가 QUEUE_OK (성공)인지 확인
    static_cast<FwAssertArgType>(qStatus) // 실패 시 상태 값 출력
);

虽然断言本身是一种调试工具,但默认系统配置
sigabort是在断言失败时发送信号并强制终止进程。因此,由于过多的命令传输导致队列溢出,引起断言失败,最终导致飞行软件进程异常终止的拒绝服务(DoS)情况。

综上所述,队列溢出时的处理应该合理设置为block、drop或者hook,而不是assert,但默认设置是应用assert,导致队列满的时候程序崩溃,从而造成漏洞。

参考
– https://www.cve.org/CVERecord?id=CVE-2024-55030

感谢您抽出

.

.

来阅读本文

点它,分享点赞在看都在这里