Search code examples
clinuxlinux-kernelnetlink

Retrieve unaligned netlink message size in kernel space


I am working on a Linux kernel module which has a bi-directional communication link with a userspace module provided by netlink.

I have an issue with an incorrect message length calculation on messages sent from userspace to kernel space. The message is sent from userspace like this:

this->sendLock.lock();
this->netlinkTxHeader->nlmsg_len = NLMSG_SPACE(len);
this->netlinkTxIov.iov_len = this->netlinkTxHeader->nlmsg_len;

memcpy(NLMSG_DATA(this->netlinkTxHeader), buf, len);

int32_t status = sendmsg(this->netlinkSock, &this->netlinkTxMsg, 0);

And is received in kernel space like this:

unsigned char* buf = (unsigned char*)NLMSG_DATA(nlh);
int len = NLMSG_PAYLOAD(nlh, 0);

However the calculated value of len always seems to be the aligned size, which I don't want. For example, I can see from debug information that the userspace process sends a message with a payload of 14 bytes (excluding netlink headers). When this is received in the kernel module, however, NLMSG_PAYLOAD returns a length of 16 bytes.

Is there any way to get the unaligned payload length (i.e. the actual payload length) back in the kernel module? I looked through the macros in netlink.h but I don't see anything which would help.

Note that the nlmsghdr object is derived using the netlink_rcv_skb() function in the kernel module.

The only other way I can see to fix this is to prefix the actual length in the payload information which I think would work, but doesn't really feel "correct".


Solution

  • See man 3 netlink: you need to use NLMSG_LENGTH(len) (and not NLMSG_SPACE(len)) to calculate the nlmsg_len field of the nlmsghdr.