Skip to content

fix: resolve CVE logs only showing entries up to 2021#425

Merged
electricface merged 1 commit into
linuxdeepin:masterfrom
electricface:swt/fix-cve-info
May 22, 2026
Merged

fix: resolve CVE logs only showing entries up to 2021#425
electricface merged 1 commit into
linuxdeepin:masterfrom
electricface:swt/fix-cve-info

Conversation

@electricface
Copy link
Copy Markdown
Member

Add parseBinaryPackages function to handle three binary field formats:

  • JSON object array: [{"name":"pkg", ...}]
  • String-encoded JSON: "[{"name":"pkg", ...}]"
  • Legacy Python-style list: ['pkg1', 'pkg2']

Refactor updateCVEMetaDataSync to use parseBinaryPackages.

PMS: TASK-387925

Add parseBinaryPackages function to handle three binary field formats:
- JSON object array: [{"name":"pkg", ...}]
- String-encoded JSON: "[{\"name\":\"pkg\", ...}]"
- Legacy Python-style list: ['pkg1', 'pkg2']

Refactor updateCVEMetaDataSync to use parseBinaryPackages.

PMS: TASK-387925
@deepin-ci-robot
Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX。我已经仔细审查了你提供的Git Diff代码。这次修改的主要目的是重构CVE二进制包的解析逻辑,将其从原有的仅支持Python风格列表(['pkg1', 'pkg2'])扩展为同时支持JSON对象数组([{"name":"pkg"}])和字符串编码的JSON,并增加了相应的单元测试。

整体来看,代码结构清晰,测试覆盖也很全面。不过,在语法逻辑、代码质量、性能和安全性方面,我仍有以下几点改进建议:

1. 语法与逻辑

  • Python风格解析的脆弱性(潜在Bug)
    parseBinaryPackages 的Fallback逻辑中,你使用了全局替换去除 [, ], ', 空格:

    str = strings.ReplaceAll(str, "[", "")
    str = strings.ReplaceAll(str, "]", "")
    str = strings.ReplaceAll(str, " ", "")
    str = strings.ReplaceAll(str, "'", "")

    问题:如果包名本身包含这些字符(例如包名中间有空格,或包含单引号),包名会被破坏。虽然Linux包名通常不含空格,但这是一种不健壮的解析方式。更严重的是,如果输入是 ['pkg1', 'pkg2'],去除所有空格后变成 'pkg1','pkg2',再按 , 分割会得到 ['pkg1', "'pkg2'"](第二个元素前可能残留单引号,取决于替换顺序,当前代码先替换空格再替换单引号,结果会是 pkg1,pkg2,看似没问题,但如果包名含有单引号如 it's,就会被替换为 its)。
    建议:如果必须兼容Python风格的列表,建议使用正则表达式提取单引号内的内容,而不是暴力的字符串替换:

    import "regexp"
    
    var pyListRe = regexp.MustCompile(`'([^']*)'`)
    
    // 在 fallback 逻辑中:
    matches := pyListRe.FindAllStringSubmatch(raw, -1)
    var pkgs []string
    for _, m := range matches {
        if m[1] != "" && m[1] != "None" {
            pkgs = append(pkgs, m[1])
        }
    }
    return pkgs
  • JSON解析失败的静默降级
    当输入以 [ 开头但不是合法的JSON时(如 [{name: "pkg"}] 缺少引号),json.Unmarshal 会失败,代码会静默进入 Fallback 逻辑。Fallback 逻辑会去掉 [] 然后按逗号分割,这会产生完全错误的结果(如把 {name: "pkg"} 当作包名)。
    建议:如果确认数据源只有这两种格式,当判定为JSON格式(以 [ 开头)但解析失败时,应该记录一条警告日志,而不是静默降级到字符串分割。

2. 代码质量

  • 变量命名不规范
    parseBinaryPackages 中,定义了切片变量 var objs []binaryObjectvar pkgs []string。但在原代码的 updateCVEMetaDataSync 中使用了 var binarys []string
    建议:在Go语言中,复数形式通常不加 s 而是加 ies 或保持单数上下文。建议将 binarys 改为 binariespackages。虽然在当前Diff中 binarys 已被删除,但请确保项目中其他地方保持一致的命名规范。

  • 错误处理与日志
    如前所述,解析异常数据时没有日志,不利于线上问题排查。建议在解析失败时增加 log.Printf 或使用项目自定义的logger。

3. 代码性能

  • 高频场景下的字符串分配
    parseBinaryPackagesupdateCVEMetaDataSync 循环中被调用。如果 cves.Cves 数量很大(例如数万条),每次调用都会产生多次字符串分配(strings.TrimSpace, strings.ReplaceAll, []byte(decoded) 转换等)。
    建议
    1. 对于 []byte(decoded) 的转换,可以直接将函数参数改为接收 []byte,或者在上游 cve.Binary 就使用 []byte
    2. 如果采用上述的正则方式替代 ReplaceAll,可以减少中间字符串的生成。
    3. 预分配切片容量:在解析JSON数组时,可以使用 pkgs := make([]string, 0, len(objs)) 来减少内存重新分配。

4. 代码安全

  • ReDoS(正则表达式拒绝服务)风险
    如果采纳了我上面建议的正则表达式 '([^']*)',它本身是安全的,不存在回溯爆炸问题。但请不要使用如 '.*?' 这种带有贪婪和懒惰匹配结合的正则去解析,在极端长字符串下可能导致ReDoS。

  • 恶意构造的JSON数据
    如果 cve.Binary 来自外部不可信源(如网络请求返回的CVE库),恶意构造的超深嵌套JSON可能会导致 json.Unmarshal 消耗大量内存和CPU。Go的标准库 encoding/json 默认没有限制嵌套深度。
    建议:如果数据源不可信,可以考虑使用 json.Decoder 并设置 DisallowUnknownFields() 或控制读取大小。


综合改进后的代码示例

以下是结合了上述建议改进后的 parseBinaryPackages 函数:

import (
	"encoding/json"
	"regexp"
	"strings"
)

type binaryObject struct {
	Name string `json:"name"`
}

// pyListRe 用于安全提取 Python 风格列表中的单引号内容
var pyListRe = regexp.MustCompile(`'([^']*)'`)

func parseBinaryPackages(raw string) []string {
	raw = strings.TrimSpace(raw)
	if raw == "None" || len(raw) == 0 {
		return nil
	}

	decoded := raw
	// 处理被二次 JSON 编码的字符串 (如 "[{\"name\":\"pkg\"}]")
	if strings.HasPrefix(decoded, "\"") {
		var s string
		if err := json.Unmarshal([]byte(decoded), &s); err == nil {
			decoded = s
		}
	}

	// 尝试解析标准 JSON 对象数组
	if strings.HasPrefix(decoded, "[") {
		var objs []binaryObject
		if err := json.Unmarshal([]byte(decoded), &objs); err == nil {
			pkgs := make([]string, 0, len(objs))
			for _, o := range objs {
				if o.Name != "" {
					pkgs = append(pkgs, o.Name)
				}
			}
			if len(pkgs) > 0 {
				return pkgs
			}
		} else {
			// TODO: 如果需要严格排查数据质量问题,可以在此添加日志
			// log.Printf("warn: failed to parse JSON format binaries: %v, raw: %s", err, decoded)
		}
	}

	// Fallback: 兼容旧版 Python 风格列表: ['pkg1', 'pkg2']
	matches := pyListRe.FindAllStringSubmatch(raw, -1)
	if len(matches) == 0 {
		return nil
	}

	pkgs := make([]string, 0, len(matches))
	for _, m := range matches {
		pkg := m[1] // m[0] 是完整匹配如 'pkg1',m[1] 是捕获组内容 pkg1
		if pkg != "" && pkg != "None" {
			pkgs = append(pkgs, pkg)
		}
	}
	
	if len(pkgs) == 0 {
		return nil
	}
	return pkgs
}

测试代码的同步修改
你的测试用例写得很棒,覆盖了主要场景。如果你采用了正则提取的Fallback逻辑,原测试用例 TestParseBinaryPackagesOldFormat 依然可以完美通过,无需修改。同时,这种写法也能自然兼容包名中包含空格的极端情况(虽然现实中极少),代码的健壮性得到了显著提升。

@electricface electricface requested a review from zhaohuiw42 May 22, 2026 05:07
@guonafu guonafu self-requested a review May 22, 2026 07:37
@deepin-ci-robot
Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: electricface, guonafu

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@electricface electricface merged commit d5b6d92 into linuxdeepin:master May 22, 2026
15 of 17 checks passed
@electricface electricface deleted the swt/fix-cve-info branch May 22, 2026 07:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants