summaryrefslogtreecommitdiff
path: root/src/libsystemd/sd-rtnl/rtnl-message.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd/sd-rtnl/rtnl-message.c')
-rw-r--r--src/libsystemd/sd-rtnl/rtnl-message.c49
1 files changed, 36 insertions, 13 deletions
diff --git a/src/libsystemd/sd-rtnl/rtnl-message.c b/src/libsystemd/sd-rtnl/rtnl-message.c
index edf5672354..c9f348704d 100644
--- a/src/libsystemd/sd-rtnl/rtnl-message.c
+++ b/src/libsystemd/sd-rtnl/rtnl-message.c
@@ -1019,12 +1019,17 @@ int socket_write_message(sd_rtnl *nl, sd_rtnl_message *m) {
*/
int socket_read_message(sd_rtnl *rtnl) {
_cleanup_free_ void *buffer = NULL;
+ uint8_t cred_buffer[CMSG_SPACE(sizeof(struct ucred))];
+ struct iovec iov = {};
+ struct msghdr msg = {
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ .msg_control = cred_buffer,
+ .msg_controllen = sizeof(cred_buffer),
+ };
+ struct cmsghdr *cmsg;
+ bool auth = false;
struct nlmsghdr *new_msg;
- union {
- struct sockaddr sa;
- struct sockaddr_nl nl;
- } addr;
- socklen_t addr_len = sizeof(addr);
size_t need, len;
int r, ret = 0;
@@ -1038,19 +1043,37 @@ int socket_read_message(sd_rtnl *rtnl) {
if (!buffer)
return -ENOMEM;
- r = recvfrom(rtnl->fd, buffer, need, 0, &addr.sa, &addr_len);
+ iov.iov_base = buffer;
+ iov.iov_len = need;
+
+ r = recvmsg(rtnl->fd, &msg, 0);
if (r < 0)
- return (errno == EAGAIN) ? 0 : -errno; /* no data */
+ /* no data */
+ return (errno == EAGAIN) ? 0 : -errno;
else if (r == 0)
- return -ECONNRESET; /* connection was closed by the kernel */
- else if (addr_len != sizeof(addr.nl) ||
- addr.nl.nl_family != AF_NETLINK)
- return -EIO; /* not a netlink message */
- else if (addr.nl.nl_pid != 0)
- return 0; /* not from the kernel */
+ /* connection was closed by the kernel */
+ return -ECONNRESET;
else
len = (size_t)r;
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_CREDENTIALS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+ struct ucred *ucred = (void *)CMSG_DATA(cmsg);
+
+ /* from the kernel */
+ if (ucred->uid == 0 && ucred->pid == 0) {
+ auth = true;
+ break;
+ }
+ }
+ }
+
+ if (!auth)
+ /* not from the kernel, ignore */
+ return 0;
+
for (new_msg = buffer; NLMSG_OK(new_msg, len); new_msg = NLMSG_NEXT(new_msg, len)) {
_cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
const NLType *nl_type;