Page 37 - 《软件学报》2026年第7期
P. 37

2722                                                       软件学报  2026  年第  37  卷第  7  期


                 定义了扩展类中的外部方法, 以第           15–18  行为例, 调用名为   SerializeToString  的  Python  外部方法指向  C  函数实现
                 PyUpb_Message_SerializeToString. 如图  2  右下方  proto.py  所示, Python  无法区分  message.SerializeToString  是
                 C/C++实现的外部函数还是        Python  本地函数; 其实参中的位置参数和关键字参数被分别打包传给对应的                     C  实现
                 PyUpb_Message_SerializeToString (message.c 第  2–12  行), 再由  Python/C API 函数  PyArg_ParseTupleAndKeywords
                 进行解包和跨语言的类型转换, 其中格式化串“|p”要求                Python  侧接收一个  bool 类型的可选参数, 并转换为        C  中
                 int 类型的  0/1  值. 在  Python 3.13  版本中, 格式化串支持可嵌套的  37  种格式化单元, Python-C/C++互操作漏洞检查
                 器  CPyChecker 受限于其支持的    Python  版本较低, 无法识别格式化单元       p, 导致会产生一个误报.

                      // protobuf/python/message.c                 // protobuf/python/message.c
                      #include “Python.h”                           static PyType_Slot PyUpb_Message_Slots[] = {
                      PyObject* PyUpb_Message_SerializeToString(      {Py_tp_methods, PyUpb_Message_Methods},
                        PyObject* _self, PyObject* args, PyObject* kwargs) {      {0, NULL}};
                       PyUpb_Message* self = (void*)_self;
                       if (!PyUpb_Message_Verify((PyObject*)self))      PyType_Spec PyUpb_Message_Spec = {
                        return NULL;                                PYUPB_MODULE_NAME “.Message”,
                       static const char* kwlist[] = {“deterministic”, NULL};      sizeof(PyUpb_Message),
                       int deterministic = 0;                       0,
                       if (!PyArg_ParseTupleAndKeywords(            Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
                          args, kwargs, “|p” , (char**)(kwlist), &deterministic))      PyUpb_Message_Slots,};
                        return NULL;
                      ...}          CPyChecker: warning
                                                                   # protobuf/python/google/protobuf/proto.py
                      static PyMethodDef PyUpb_Message_Methods[] = {     from google.protobuf.message import Message
                       {“SerializeToString”,                       def serialize(message: Message,
                        (PyCFunction)PyUpb_Message_SerializeToString,       deterministic: bool = None) -> bytes:
                        METH_VARARGS | METH_KEYWORDS,               return message.SerializeToString(
                        “Serializes the message to a string, ...”},       deterministic=deterministic)
                       {NULL, NULL}};

                                       图 2 protobuf 互操作实例及    CPyChecker 漏洞检查误报

                  2   漏洞模式分类

                    为了系统地分类定义        Python-C/C++互操作程序可能存在的安全漏洞, 本文完整地分析整理                  Python/C API 官
                 方文档中提到的安全隐患, 并设计实现对应的漏洞模式和测试用例; 同时针对已有的不同语言的互操作安全性分
                 析研究提及的漏洞, 根据其语言特性和运行时行为的异同对漏洞模式进行了归纳和完整测例设计实现.
                    漏洞模式分析整理的来源包括: (1) Python 3.13       版本  Python/C API 官方文档; (2) 已有的  Python-C/C++跨语言
                 互操作安全性分析研究和工具           [9−17] ; (3) 已有的其他语言互操作安全性研究      [8,18] ; (4) CVE  库及  Python-C/C++互操
                 作软件开源漏洞列表. 计算机专业的一名研究生和一名本科生分别通读上述文献并实现了其中所有示例代码和漏
                 洞, 包括文档中所有提及可能存在隐患的情形, 以及其他语言的外部调用漏洞在                           Python  中对应的情形, 同时对
                 Python 3.13  版本有变更的漏洞模式进行了调整. 在两名具有博士学位和相关研究背景的专家的指导下, 对两位学
                 生实现的漏洞进行了审计、整理和分类. 如图              3  所示为漏洞模式分类流程图.
                    具体而言, 首先在语言特性层面, 我们根据导致漏洞的语言特性差异将其归纳为                            5  大类, 分别是内存模型
                 (memory model, M)、类型系统  (type system, T)、异常处理  (exception handling, E)、并发控制  (concurrency control, C)
                 和数值计算    (numerical computation, N). 这一抽象层对应  Python  与  C/C++在语言设计上的本质差异, 是引发安全
                 漏洞的根本原因      [9] . 其次, 针对每大类语言特性, 可能存在多小类的漏洞模式, 每个小类对应                 Python-C/C++互操作
                 中的一类行为     (Python/C API 集合). 以内存模型大类为例, 其可以进一步分为引用计数错误、内存管理错误和缓
                 冲区溢出这    3  小类. 最后, 根据漏洞实际的运行时行为, 每一小类又包含若干种细粒度的漏洞模式. 每种细粒度漏
   32   33   34   35   36   37   38   39   40   41   42