Skip to content

fix: replace xxd dependency with printf for hex decoding#235

Open
mhduiy wants to merge 1 commit intolinuxdeepin:masterfrom
mhduiy:xxd
Open

fix: replace xxd dependency with printf for hex decoding#235
mhduiy wants to merge 1 commit intolinuxdeepin:masterfrom
mhduiy:xxd

Conversation

@mhduiy
Copy link
Contributor

@mhduiy mhduiy commented Feb 7, 2026

Changed hex decoding method from xxd to printf with sed transformation to handle hex-encoded paths parameter without external dependencies. The previous implementation required xxd command which might not be available in all environments. The new approach uses sed to convert each hex pair to \x escape sequences, then printf interprets them as binary data, providing a pure bash solution that is more portable.

fix: 移除对 xxd 的依赖,改用 printf 进行十六进制解码

将十六进制解码方法从 xxd 改为使用 printf 配合 sed 转换,以处理十六进制
编码的路径参数,无需外部依赖。之前的实现需要 xxd 命令,但该命令可能并非
在所有环境中都可用。新方法使用 sed 将每个十六进制对转换为 \x 转义序列,
然后使用 printf 将其解释为二进制数据,提供了一个纯 bash 解决方案,具有
更好的可移植性。

PMS: BUG-349711

Changed hex decoding method from xxd to printf with sed transformation
to handle hex-encoded paths parameter without external dependencies.
The previous implementation required xxd command which might not be
available in all environments. The new approach uses sed to convert
each hex pair to \x escape sequences, then printf interprets them as
binary data, providing a pure bash solution that is more portable.

fix: 移除对 xxd 的依赖,改用 printf 进行十六进制解码

将十六进制解码方法从 xxd 改为使用 printf 配合 sed 转换,以处理十六进制
编码的路径参数,无需外部依赖。之前的实现需要 xxd 命令,但该命令可能并非
在所有环境中都可用。新方法使用 sed 将每个十六进制对转换为 \x 转义序列,
然后使用 printf 将其解释为二进制数据,提供了一个纯 bash 解决方案,具有
更好的可移植性。

PMS: BUG-349711
@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: mhduiy

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

@deepin-ci-robot
Copy link

deepin pr auto review

这段代码修改的目的是将十六进制编码的字符串解码为可读文本。原代码使用 xxd 工具,新代码使用 printfsed 组合。以下是对这段 diff 的详细审查和改进建议:

1. 语法逻辑审查

  • 修改前: xxd -r -p 是标准的十六进制转储反转命令,能够处理包含空格或换行的标准十六进制字符串。
  • 修改后: sed 's/../\\x&/g' 将每两个字符前插入 \x,然后利用 printf '%b' 解释转义字符。
    • 潜在逻辑问题: printf '%b' 的行为依赖于 shell 环境。虽然 Bash 的 printf 支持十六进制转义(\xHH),但这在 POSIX 标准中并不是强制的。如果此脚本需要在非 Bash 环境(如 strict POSIX sh 或某些精简版 shell)下运行,可能会报错或无法正确解码。
    • 兼容性: xxd 通常属于 vim-common 包,而 printf 是 shell 内置。修改可能是为了减少外部依赖,但牺牲了标准十六进制格式的宽容度(例如无法处理 xxd 输出中可能存在的空格)。

2. 代码质量审查

  • 可读性: 新代码使用了命令替换嵌套和 sed 正则,对于不熟悉 \x 转义机制的开发者来说,可读性略低于直接使用 xxd
  • 健壮性:
    • 如果 $ENCODED_PARAM 包含奇数个字符(非法的十六进制字符串),sed 会在最后一个字符前插入 \x,导致 printf 报错(如 printf: invalid hex number)。
    • 原代码 xxd 对奇数个字符的处理通常是忽略最后一个字符或报错,取决于版本,但通常不会导致 shell 脚本中断(因为有 || echo "")。
    • 新代码虽然有 2>/dev/null,但在某些 shell 中,printf 的格式错误可能输出到 stdout 而非 stderr,或者导致脚本非预期退出。

3. 代码性能审查

  • 执行效率: xxd 是编译好的二进制工具,处理长字符串通常非常快。新方案启动了一个 sed 进程和一个 printf 内置命令。
  • 开销: 对于极短的字符串,性能差异可忽略不计。但如果 $ENCODED_PARAM 非常大(例如几 MB 的日志),sed 处理正则替换和管道传输的开销会明显高于 xxd。因此,对于大数据量,原方案性能更好。

4. 代码安全审查

  • 命令注入风险:
    • 原代码: echo "$ENCODED_PARAM" | xxd -r -p。如果 $ENCODED_PARAM 包含例如 -e 等看起来像选项的字符串,xxd 可能会误解。虽然 -p 模式下通常只处理纯十六进制,但依赖外部命令解析用户输入始终存在一定风险。
    • 新代码: printf '%b' "..."这是严重的安全隐患printf '%b' 会解释反斜杠转义序列。如果解码后的内容(即十六进制解码后的结果)中包含恶意的转义序列(例如 %n 在某些实现中可能导致写入,或者仅仅是控制字符改变终端状态),可能会造成问题。更严重的是,如果 $ENCODED_PARAM 经过十六进制解码后,其内容恰好构成了对 printf 格式化字符串有意义的字符(虽然 %b 后面跟的是字符串参数,而非格式串,风险相对较低,但仍需注意)。
    • 具体场景: 如果攻击者能够控制 $ENCODED_PARAM,他们可以构造特定的十六进制串,解码后包含 %s\n 等,虽然在这里只是打印到变量,但如果后续代码将此变量传递给其他 eval 或格式化函数,风险会放大。
    • 改进建议: 确保解码后的内容仅被视为纯数据,而不是可执行代码或格式化字符串。

5. 综合改进建议

如果目标是去除 xxd 依赖且保持 Bash 兼容性,建议使用以下更安全、更健壮的方法:

方案 A:使用 Bash 内置特性(推荐,如果确定运行环境是 Bash)
Bash 的 echo 在某些版本支持 -e,但这不可靠。最稳妥的方式是利用变量替换和 printf%x 反向操作(较复杂),或者直接使用 xxd(如果依赖允许)。

如果必须替换 xxd,且假设输入是合法的十六进制字符串,可以使用以下代码,它对奇数长度有更好的容错,且避免了复杂的 sed 管道:

# 检查长度是否为偶数,否则补零或报错
if [ $(( ${#ENCODED_PARAM} % 2 )) -ne 0 ]; then
    # error_exit "Invalid hex string length" 
    # 或者简单地补个0,视业务逻辑而定
    ENCODED_PARAM="${ENCODED_PARAM}0"
fi

# 使用循环逐字节处理,最安全但最慢(适用于短字符串)
PATHS_PARAM=""
while [ -n "$ENCODED_PARAM" ]; do
    # 取前两个字符
    hex_byte="${ENCODED_PARAM:0:2}"
    # 转换为 ASCII 并追加
    PATHS_PARAM+="${hex_byte}" # 这里需要转义,见下文
    # 移除已处理部分
    ENCODED_PARAM="${ENCODED_PARAM:2}"
done

# 上述循环在 Bash 中可以通过 printf 更优雅地实现:
# 但要注意,直接 printf "${ENCODED_PARAM//../\\x&}" 仍然存在奇数长度问题

方案 B:优化原修改(针对 Bash)

如果坚持使用 printfsed,建议增加对输入长度的检查,并确保错误处理覆盖 printf 的输出:

# 检查是否为有效的十六进制字符串(仅含 0-9a-fA-F)且长度为偶数
if [[ "$ENCODED_PARAM" =~ ^[0-9a-fA-F]+$ ]] && [ $(( ${#ENCODED_PARAM} % 2 )) -eq 0 ]; then
    # 使用 sed 替换,并确保 printf 的错误被捕获
    # 注意:这里假设是 Bash
    PATHS_PARAM=$(printf '%b' "${ENCODED_PARAM//../\\x}" 2>/dev/null) || PATHS_PARAM=""
else
    PATHS_PARAM=""
fi

if [ -z "$PATHS_PARAM" ]; then
    error_exit "Failed to decode hex parameter: Invalid input"
fi

方案 C:使用 Python(如果环境允许)

如果系统中有 Python(通常比 xxd 更常见),这是最安全且最跨平台的方式:

PATHS_PARAM=$(python3 -c "import sys, binascii; print(binascii.unhexlify(sys.stdin.read().strip()).decode('utf-8', errors='replace'))" <<< "$ENCODED_PARAM") || PATHS_PARAM=""

优点: 完美处理错误、编码问题,不需要复杂的 shell 转义。
缺点: 启动 Python 解释器较慢。

总结

原 diff 的修改引入了 兼容性风险(非 POSIX shell)和 安全风险printf 解释转义符)。如果必须去除 xxd 依赖,建议采用 方案 B 并增加输入校验;如果允许外部依赖,保留 xxd 或使用 Python(方案 C)是更好的选择。

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.

2 participants