netlink: loosen sender checks to allow other multicast messages
We need the IFLA_PROTINFO messages, and these are apparently sent (still by the kernel) but with our own PID. So the current checks that limit the netlink PID to zero block these messages out. Instead (like udev) we should be checking the actual sender of the message usign unix socket credentials. Second, at least at this point only privileged processes can send netlink multicast messages, so as long as the: * the other end of the socket is UID 0 AND * the netlink PID is 0 OR * the message is multicast and sent to our netlink PID the we accept the message and process it as normal. For another example of this, see 'netlink.c' from the dhcp6s program; do a Google search for "IFLA_PROTINFO" to find it.
This commit is contained in:
@@ -25,6 +25,9 @@
|
||||
* Copyright (C) 2004 Novell, Inc.
|
||||
*/
|
||||
|
||||
/* for struct ucred */
|
||||
#include <config.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
@@ -209,15 +212,41 @@ out:
|
||||
static int
|
||||
netlink_event_input (struct nl_msg *msg, void *arg)
|
||||
{
|
||||
NMNetlinkMonitor *self = NM_NETLINK_MONITOR (arg);
|
||||
NMNetlinkMonitorPrivate *priv = NM_NETLINK_MONITOR_GET_PRIVATE (self);
|
||||
struct nlmsghdr *hdr = nlmsg_hdr (msg);
|
||||
struct ucred *creds = nlmsg_get_creds (msg);
|
||||
guint32 local_port;
|
||||
gboolean accept_msg = FALSE;
|
||||
|
||||
if (hdr->nlmsg_pid != 0)
|
||||
/* Only messages sent from the kernel */
|
||||
if (!creds || creds->uid != 0) {
|
||||
nm_log_dbg (LOGD_HW, "ignoring netlink message from UID %d",
|
||||
creds ? creds->uid : -1);
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
/* Accept any messages from the kernel */
|
||||
if (hdr->nlmsg_pid == 0)
|
||||
accept_msg = TRUE;
|
||||
|
||||
/* And any multicast message directed to our netlink PID, since multicast
|
||||
* currently requires CAP_ADMIN to use.
|
||||
*/
|
||||
local_port = nl_socket_get_local_port (priv->nlh);
|
||||
if ((hdr->nlmsg_pid == local_port) && (hdr->nlmsg_flags & NLM_F_MULTI))
|
||||
accept_msg = TRUE;
|
||||
|
||||
if (accept_msg == FALSE) {
|
||||
nm_log_dbg (LOGD_HW, "ignoring netlink message from PID %d (local PID %d, multicast %d)",
|
||||
hdr->nlmsg_pid,
|
||||
local_port,
|
||||
(hdr->nlmsg_flags & NLM_F_MULTI));
|
||||
return NL_STOP;
|
||||
}
|
||||
|
||||
nl_msg_parse (msg, &netlink_object_message_handler, arg);
|
||||
|
||||
/* Stop processing messages */
|
||||
return NL_STOP;
|
||||
return NL_SKIP;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -304,6 +333,14 @@ nm_netlink_monitor_open_connection (NMNetlinkMonitor *monitor,
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (nl_set_passcred (priv->nlh, 1) < 0) {
|
||||
g_set_error (error, NM_NETLINK_MONITOR_ERROR,
|
||||
NM_NETLINK_MONITOR_ERROR_NETLINK_CONNECT,
|
||||
_("unable to enable netlink handle credential passing: %s"),
|
||||
nl_geterror ());
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (nl_socket_add_membership (priv->nlh, RTNLGRP_LINK) < 0) {
|
||||
g_set_error (error, NM_NETLINK_MONITOR_ERROR,
|
||||
NM_NETLINK_MONITOR_ERROR_NETLINK_JOIN_GROUP,
|
||||
|
Reference in New Issue
Block a user