当我运行以下代码时,我尝试使用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()
)包含一个条件,该条件实质上禁止NLA_UNSPEC
使用。
我不确定是否可以禁用该验证。validate_nla()
硬代码 validate
as的主要用户NL_VALIDATE_STRICT
,其中包含NL_VALIDATE_UNSPEC
。
但是无论如何,我建议您不要使用NLA_UNSPEC
未经适当的序列化发送C结构。等待发生的灾难。C有一个陷阱,叫做“数据结构填充”;要点是允许C编译器在任何结构的成员之间引入垃圾。因此,当您声明时:
struct test {
__u16 a;
__u32 b;
};
从技术上讲,允许编译器在实现过程中将其更改为类似
struct test {
__u16 a;
unsigned char garbage[2];
__u32 b;
};
看到问题了吗?如果内核模块和用户空间客户端是由不同的编译器生成的,或者由相同的编译器生成的,但是它们的标志略有不同,甚至是由同一编译器的稍有不同的版本生成的,则结构可能会有所不同,并且内核将收到垃圾,无论如何更正您的代码外观。
使用嵌套属性而不是NLA_UNSPEC
。他们会为您调整位置。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句