求助:IPMI SetCommandEnables (0x06 0x60) 命令返回成功但掩码不生效
环境信息
| 项目 | 值 |
|------|-----|
| 固件版本 | openUBMC 0630|
| 测试脚本 | test-firewall.sh |
问题描述
IPMI SetCommandEnables (NetFn=0x06, Cmd=0x60) 命令执行后返回 success(exit code 0),但 GetCommandEnables 查询到的掩码从未被修改,目标命令也未被禁用。
复现步骤
# 1. 查询初始掩码(成功,返回 16 字节)
$ ipmitool -I lanplus -H 90.90.124.10 -U USER -P PASS \
raw 0x06 0x61 0x01 0x06 0x00
de 17 00 00 34 c0 fb 1d ff ff f4 03 03 00 00 00
# 2. 验证目标命令可执行(Get Device GUID,成功)
$ ipmitool -I lanplus -H 90.90.124.10 -U USER -P PASS \
raw 0x06 0x08
21 10 12 02 26 20 4d 86 11 f1 3e dc c5 be 49 10
# 3. 修改掩码禁用 cmd 0x08(byte[1] bit0: 0x17 -> 0x16)并 Set(返回 success!)
$ ipmitool -I lanplus -H 90.90.124.10 -U USER -P PASS \
raw 0x06 0x60 0x01 0x06 0x00 \
0xde 0x16 0x00 0x00 0x34 0xc0 0xfb 0x1d 0xff 0xff 0xf4 0x03 0x03 0x00 0x00 0x00
# exit=0, 无错误输出
# 4. 再次查询掩码 —— 和步骤1完全一样,byte[1] 仍是 0x17 不是 0x16
$ ipmitool -I lanplus -H 90.90.124.10 -U USER -P PASS \
raw 0x06 0x61 0x01 0x06 0x00
de 17 00 00 34 c0 fb 1d ff ff f4 03 03 00 00 00 ← 掩码未变!
# 5. cmd 0x08 仍然能执行
$ ipmitool -I lanplus -H 90.90.124.10 -U USER -P PASS \
raw 0x06 0x08
21 10 12 02 26 20 4d 86 11 f1 3e dc c5 be 49 10 ← 命令仍然成功
排查过程
1. 请求头格式验证
IPMI 规范(v2.0 §22.27)定义请求头为位域打包格式:
byte[0] = (ChannelNum << 4) | Reserved
byte[1] = (NetFN << 2) | Operation
byte[2] = (LUN << 6) | Reserved
测试结果:发送打包 header 0x10 0x18 0x00 时 GetCommandEnables 返回 rsp=0xcc(Invalid data field)。发送 raw bytes 0x01 0x06 0x00 时正常工作。结论:handler 读 raw bytes,不做位域解包。
2. EnableMask 长度验证
| 尝试的格式 | 结果 |
|-----------|------|
| 1 字节(仅 cmd) | rsp=0xff |
| 2 字节(cmd+enable pair) | rsp=0xff |
| 16 字节(完整 bitmap,与 Get 返回一致) | exit=0(success)但掩码不变 |
3. 相关命令交叉验证
| 命令 | NetFn/Cmd | 结果 |
|------|-----------|------|
| GetCommandEnables | 0x06/0x61 | 返回 de 17 00 00 34 c0 fb 1d ff ff f4 03 03 00 00 00 |
| GetConfigurableCommands | 0x06/0x0c | 返回 完全相同 的掩码 |
| GetCommandSupport | 0x06/0x0a | 返回 de 17 00 00... (同上) |
三个查询命令返回完全相同的掩码,说明它们可能读取同一份数据。
4. Black/White List 启用尝试
尝试通过 BWListOpenClose (0x30/0x93) 启用 blacklist mode,但命令失败(尝试了多种 Manufacturer ID 字节序均失败)。
疑问
-
SetCommandEnables 是否需要先通过 BWListOpenClose 启用 black/white list mode 才能生效? 如果需要,正确的调用方式和参数是什么?
-
GetConfigurableCommands 和 GetCommandEnables 返回相同掩码是设计如此,还是 GetCommandEnables 实际返回的是 Configurable 掩码? 在 IPMI 规范中这两个命令返回的数据含义不同。
-
EnableMask 的正确格式是什么? 是 16 字节 bitmap(与 Get 返回一致)还是 cmd+enable pair 列表?16 字节格式返回 success 但不生效,pair 格式返回
rsp=0xff。 -
handler 对请求头的解析方式:
ipmi_core/mds/ipmi.json定义为位域打包格式,但实际 handler 读 raw bytes(打包 header 返回0xcc)。这是一个 bug 还是设计如此? -
固件版本中 SetCommandEnables 是否完整实现了写入逻辑? 从现象看,handler 接受了请求(返回 success)但没有实际修改共享内存中的掩码数据。
相关代码路径
-
命令定义:
ipmi_core/mds/ipmi.json→SetCommandEnables/GetCommandEnables -
handler 实现:
ipmi_core/lualib/commands/ipmi_firewall_cmds.lua闭源 -
黑/白名单管理:
ipmi_core/lualib/ipmi/bw_ipmi_cmd_mgmt.lua闭源
测试脚本
test-firewall.sh
#!/bin/bash -e
BMC_IP="70.183.12.111"
USERNAME="..."
PASSWORD="..."
TARGET_NETFN="0x06"
TARGET_CMD="0x08"
CHANNEL="0x01"
LUN="0x00"
parse_hex_output() {
local output="$1"
echo "$output" | grep -oE '[0-9a-fA-F]{2}' | sed 's/^/0x/' | tr '\n' ' '
}
echo "=== 测试开始 ==="
# 1. 查询初始命令启用状态
echo "1. 查询初始命令启用状态 (GetCommandEnables)"
GET_OUTPUT=$(ipmitool -I lanplus -H $BMC_IP -U $USERNAME -P $PASSWORD raw 0x06 0x61 $CHANNEL $TARGET_NETFN $LUN)
echo "初始掩码: $GET_OUTPUT"
echo " "
# 2. 验证目标命令可正常执行
echo "2. 验证目标命令可正常执行"
ipmitool -I lanplus -H $BMC_IP -U $USERNAME -P $PASSWORD raw $TARGET_NETFN $TARGET_CMD
if [ $? -eq 0 ]; then
echo "命令执行成功"
else
echo "命令执行失败,请检查命令是否正确"
exit 1
fi
echo " "
# 3. 查询可配置命令(确认目标命令可被禁用)
echo "3. 查询可配置命令 (GetConfigurableCommands)"
CFG_OUTPUT=$(ipmitool -I lanplus -H $BMC_IP -U $USERNAME -P $PASSWORD raw 0x06 0x0c $CHANNEL $TARGET_NETFN $LUN)
echo "可配置掩码: $CFG_OUTPUT"
echo " "
# 4. 禁用目标命令
echo "4. 禁用目标命令 (SetCommandEnables)"
MASK_BYTES=($(parse_hex_output "$GET_OUTPUT"))
if [ ${#MASK_BYTES[@]} -ne 16 ]; then
echo "错误:掩码字节数不是16,实际为 ${#MASK_BYTES[@]}"
exit 1
fi
CMD_VALUE=$((TARGET_CMD))
BYTE_INDEX=$((CMD_VALUE / 8))
BIT_OFFSET=$((CMD_VALUE % 8))
BIT_MASK=$((1 << BIT_OFFSET))
echo "命令 $TARGET_CMD 对应字节索引 $BYTE_INDEX,位偏移 $BIT_OFFSET"
ORIG_BYTE_VAL=${MASK_BYTES[$BYTE_INDEX]#0x}
ORIG_BYTE_VAL=$((16#$ORIG_BYTE_VAL))
NEW_BYTE_VAL=$((ORIG_BYTE_VAL & ~BIT_MASK))
MASK_BYTES[$BYTE_INDEX]=$(printf "0x%02x" $NEW_BYTE_VAL)
echo "原字节: $(printf "0x%02x" $ORIG_BYTE_VAL) -> 新字节: $(printf "0x%02x" $NEW_BYTE_VAL)"
SET_ARGS=("$CHANNEL" "$TARGET_NETFN" "$LUN" "${MASK_BYTES[@]}")
echo "执行: ipmitool raw 0x06 0x60 ... ${#SET_ARGS[@]} 字节"
ipmitool -I lanplus -H $BMC_IP -U $USERNAME -P $PASSWORD raw 0x06 0x60 "${SET_ARGS[@]}"
echo "Set 执行完毕"
echo " "
# 5. 验证掩码是否真的被修改
echo "5. 验证掩码是否被修改"
NEW_GET_OUTPUT=$(ipmitool -I lanplus -H $BMC_IP -U $USERNAME -P $PASSWORD raw 0x06 0x61 $CHANNEL $TARGET_NETFN $LUN)
echo "禁用后掩码: $NEW_GET_OUTPUT"
if [ "$GET_OUTPUT" = "$NEW_GET_OUTPUT" ]; then
echo ""
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo "!! SetCommandEnables 掩码未变更 !!"
echo "!! BMC 固件的 SetCommandEnables 实现存在 bug:"
echo "!! - handler 接受了请求(返回 success)"
echo "!! - 但掩码数据未被实际写入"
echo "!! - 可能原因:black/white list mode 未启用"
echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
echo ""
exit 1
fi
echo "掩码已变更 ✓"
echo " "
# 6. 验证目标命令执行失败
echo "6. 验证目标命令执行失败"
set +e
ipmitool -I lanplus -H $BMC_IP -U $USERNAME -P $PASSWORD raw $TARGET_NETFN $TARGET_CMD
CMD_EXIT=$?
set -e
if [ $CMD_EXIT -ne 0 ]; then
echo "命令执行失败(符合预期)"
else
echo "命令执行成功(不符合预期)"
exit 1
fi
echo " "
# 7. 恢复目标命令
echo "7. 恢复目标命令"
MASK_BYTES[$BYTE_INDEX]=$(printf "0x%02x" $ORIG_BYTE_VAL)
RESTORE_ARGS=("$CHANNEL" "$TARGET_NETFN" "$LUN" "${MASK_BYTES[@]}")
echo "执行: ipmitool raw 0x06 0x60 ... ${#RESTORE_ARGS[@]} 字节"
ipmitool -I lanplus -H $BMC_IP -U $USERNAME -P $PASSWORD raw 0x06 0x60 "${RESTORE_ARGS[@]}"
echo " "
# 8. 查询命令恢复后的状态
echo "8. 查询命令恢复后的状态"
RESTORE_GET_OUTPUT=$(ipmitool -I lanplus -H $BMC_IP -U $USERNAME -P $PASSWORD raw 0x06 0x61 $CHANNEL $TARGET_NETFN $LUN)
echo "恢复后掩码: $RESTORE_GET_OUTPUT"
echo " "
# 9. 验证目标命令可正常执行
echo "9. 验证目标命令可正常执行"
ipmitool -I lanplus -H $BMC_IP -U $USERNAME -P $PASSWORD raw $TARGET_NETFN $TARGET_CMD
if [ $? -eq 0 ]; then
echo "命令执行成功"
else
echo "命令执行失败"
exit 1
fi
echo " "
echo "=== 测试结束 ==="