尝试通过 libnl 和通用 netlink 发送抽象数据时出错
Error trying to send an abstract data through libnl and generic netlink
我正在尝试使用 libnl 和通用 netlink 发送抽象数据,当我 运行 以下代码时:
struct nl_msg *msg;
struct nl_data *abstract;
int err = -1;
if ((msg = nlmsg_alloc()) == NULL)
return err;
if ((genlmsg_put(msg, ctrl->pid, NL_AUTO_SEQ, ctrl->genl_family,
0, NLM_F_REQUEST, CREATE_STATE, KLUA_VERSION) == NULL))
return err;
if ((err = nla_put_string(msg, STATE_NAME, cmd->name)))
return err;
if ((err = nl_send_auto(ctrl->sock, msg)) < 0)
return err;
nlmsg_free(msg);
内核很好地接收了消息。但是如果我为此更改此代码:
struct nl_msg *msg;
struct nl_data *abstract;
int err = -1;
if ((msg = nlmsg_alloc()) == NULL)
return err;
if ((abstract = nl_data_alloc(cmd, sizeof(struct klua_nl_state))) == NULL)
return err;
if ((genlmsg_put(msg, ctrl->pid, NL_AUTO_SEQ, ctrl->genl_family,
0, NLM_F_REQUEST, CREATE_STATE, KLUA_VERSION) == NULL))
return err;
nla_put_data(msg, TEST_ATTR, abstract);
if ((err = nl_send_auto(ctrl->sock, msg)) < 0)
return err;
nlmsg_free(msg);
顺便说一句,我的TEST_ATTR
定义为:
[TEST_ATTR] = {.type = NLA_UNSPEC}
如果我只更改消息的负载,为什么内核收不到我的消息?
如何通过通用 netlink 和 libnl 发送抽象数据?
从Linux 5.2开始,内核的属性验证器函数(validate_nla()
) contains a conditional实质上禁止NLA_UNSPEC
被使用。
我不确定是否可以禁用该验证。 validate_nla()
hardcodes validate
as NL_VALIDATE_STRICT
, which contains NL_VALIDATE_UNSPEC
.
的主要用户
但无论如何,我建议您不要使用 NLA_UNSPEC
在没有适当序列化的情况下发送 C 结构。这是一场等待发生的灾难。 C 有一个陷阱叫做“data structure padding;”它的要点是允许 C 编译器在任何结构的成员之间引入垃圾。因此,当您声明时:
struct test {
__u16 a;
__u32 b;
};
技术上允许编译器在实现过程中将其突变为类似
的东西
struct test {
__u16 a;
unsigned char garbage[2];
__u32 b;
};
看到问题了吗?如果你的内核模块和你的用户空间客户端是由不同的编译器生成的,或者是由同一个编译器生成的但标志略有不同,或者甚至是由同一个编译器的稍微不同的版本生成的,结构可能不同并且无论您的代码看起来多么正确,内核都会收到垃圾。
使用 Nested Attributes 而不是 NLA_UNSPEC
。他们会为您安排对齐。
我正在尝试使用 libnl 和通用 netlink 发送抽象数据,当我 运行 以下代码时:
struct nl_msg *msg;
struct nl_data *abstract;
int err = -1;
if ((msg = nlmsg_alloc()) == NULL)
return err;
if ((genlmsg_put(msg, ctrl->pid, NL_AUTO_SEQ, ctrl->genl_family,
0, NLM_F_REQUEST, CREATE_STATE, KLUA_VERSION) == NULL))
return err;
if ((err = nla_put_string(msg, STATE_NAME, cmd->name)))
return err;
if ((err = nl_send_auto(ctrl->sock, msg)) < 0)
return err;
nlmsg_free(msg);
内核很好地接收了消息。但是如果我为此更改此代码:
struct nl_msg *msg;
struct nl_data *abstract;
int err = -1;
if ((msg = nlmsg_alloc()) == NULL)
return err;
if ((abstract = nl_data_alloc(cmd, sizeof(struct klua_nl_state))) == NULL)
return err;
if ((genlmsg_put(msg, ctrl->pid, NL_AUTO_SEQ, ctrl->genl_family,
0, NLM_F_REQUEST, CREATE_STATE, KLUA_VERSION) == NULL))
return err;
nla_put_data(msg, TEST_ATTR, abstract);
if ((err = nl_send_auto(ctrl->sock, msg)) < 0)
return err;
nlmsg_free(msg);
顺便说一句,我的TEST_ATTR
定义为:
[TEST_ATTR] = {.type = NLA_UNSPEC}
如果我只更改消息的负载,为什么内核收不到我的消息? 如何通过通用 netlink 和 libnl 发送抽象数据?
从Linux 5.2开始,内核的属性验证器函数(validate_nla()
) contains a conditional实质上禁止NLA_UNSPEC
被使用。
我不确定是否可以禁用该验证。 validate_nla()
hardcodes validate
as NL_VALIDATE_STRICT
, which contains NL_VALIDATE_UNSPEC
.
但无论如何,我建议您不要使用 NLA_UNSPEC
在没有适当序列化的情况下发送 C 结构。这是一场等待发生的灾难。 C 有一个陷阱叫做“data structure padding;”它的要点是允许 C 编译器在任何结构的成员之间引入垃圾。因此,当您声明时:
struct test {
__u16 a;
__u32 b;
};
技术上允许编译器在实现过程中将其突变为类似
的东西struct test {
__u16 a;
unsigned char garbage[2];
__u32 b;
};
看到问题了吗?如果你的内核模块和你的用户空间客户端是由不同的编译器生成的,或者是由同一个编译器生成的但标志略有不同,或者甚至是由同一个编译器的稍微不同的版本生成的,结构可能不同并且无论您的代码看起来多么正确,内核都会收到垃圾。
使用 Nested Attributes 而不是 NLA_UNSPEC
。他们会为您安排对齐。