尝试通过libnl和通用网络链接发送抽象数据时出错,

时间:2020-07-01 19:57:17

标签: c 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发送抽象数据?

1 个答案:

答案 0 :(得分:0)

从Linux 5.2开始,内核的属性验证器功能(validate_nla())包含一个conditional,实际上禁止使用NLA_UNSPEC

我不确定是否可以禁用该验证。 validate_nla() hardcodes validate的主要用户为NL_VALIDATE_STRICT,其中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。他们会为您调整位置。