Search code examples
clinuxnetlink

Netlink receive buffer alignment


PVS-Studio, a static analyzer, reports that in nh = (struct nlmsghdr *) buf,

The pointer 'buf' is cast to a more strictly aligned pointer type.

I think that the warning is correct. Is this a serious problem? The code needs to be portable on various architectures. How can I fix this?

I know of some ways:

  • allocate the buffer on the heap;
  • use the stdalign features, but they’re not C99,
  • the cmsghdr api uses an union to deal with the alignment, but I’m not sure if netlink does that.

Is there another option?

The code below is taken from the netlink manpage.

int len;
char buf[8192];     /* 8192 to avoid message truncation on
                       platforms with page size > 4096 */
struct iovec iov = { buf, sizeof(buf) };
struct sockaddr_nl sa;
struct msghdr msg;
struct nlmsghdr *nh;

msg = { &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
len = recvmsg(fd, &msg, 0);

for (nh = (struct nlmsghdr *) buf; NLMSG_OK (nh, len);
     nh = NLMSG_NEXT (nh, len)) {
     /* The end of multipart message */
     if (nh->nlmsg_type == NLMSG_DONE)
     return;

     if (nh->nlmsg_type == NLMSG_ERROR)
     /* Do some error handling */
     ...

     /* Continue with parsing payload */
     ...
}

Thanks.


Solution

  • Isn't better to take a pointer of an allocated struct nlmsghdr instead of a char buf[8192]?

    for example:

    int len;
    struct nlmsghdr buf;
    struct iovec iov = { &buf, sizeof(buf) };
    struct sockaddr_nl sa;
    struct msghdr msg;
    struct nlmsghdr *nh;
    
    msg = { &sa, sizeof(sa), &iov, 1, NULL, 0, 0 };
    len = recvmsg(fd, &msg, 0);
    
    for (nh = &buf; NLMSG_OK (nh, len);
        nh = NLMSG_NEXT (nh, len)) {
        /* The end of multipart message */
        if (nh->nlmsg_type == NLMSG_DONE)
        return;
    
        if (nh->nlmsg_type == NLMSG_ERROR)
        /* Do some error handling */
        ...
    
        /* Continue with parsing payload */
        ...
    }