Commit bf7865e8 authored by Aleksander Morgado's avatar Aleksander Morgado Committed by Dan Williams

platform: avoid storing unknown netlink object types (bgo #742928)

Testing WWAN connections through a Nokia Series 40 phone, addresses of family
AF_PHONET end up triggering an assert() in object_has_ifindex(), just because
object_type_from_nl_object() only handles AF_INET and AF_INET6 address.

In order to avoid this kind of problems, we'll try to make sure that the object
caches kept by NM only store known object types.

(fixup by dcbw to use cached passed to cache_remove_unknown())

https://bugzilla.gnome.org/show_bug.cgi?id=742928

    Connect: ppp0 <--> /dev/ttyACM0
    nm-pppd-plugin-Message: nm-ppp-plugin: (nm_phasechange): status 5 / phase 'establish'
    NetworkManager[27434]: <info>  (ppp0): new Generic device (driver: 'unknown' ifindex: 12)
    NetworkManager[27434]: <info>  (ppp0): exported as /org/freedesktop/NetworkManager/Devices/4
    [Thread 0x7ffff1ecf700 (LWP 27439) exited]
    NetworkManager[27434]: <info>  (ttyACM0): device state change: ip-config -> deactivating (reason 'user-requested') [70 110 39]
    Terminating on signal 15
    nm-pppd-plugin-Message: nm-ppp-plugin: (nm_phasechange): status 10 / phase 'terminate'
    **
    NetworkManager:ERROR:platform/nm-linux-platform.c:1534:object_has_ifindex: code should not be reached

    Program received signal SIGABRT, Aborted.
    0x00007ffff4692a97 in raise () from /usr/lib/libc.so.6
    (gdb) bt
    #0  0x00007ffff4692a97 in raise () from /usr/lib/libc.so.6
    #1  0x00007ffff4693e6a in abort () from /usr/lib/libc.so.6
    #2  0x00007ffff4c8d7f5 in g_assertion_message () from /usr/lib/libglib-2.0.so.0
    #3  0x00007ffff4c8d88a in g_assertion_message_expr () from /usr/lib/libglib-2.0.so.0
    #4  0x0000000000472b91 in object_has_ifindex (object=0x8a8320, ifindex=12) at platform/nm-linux-platform.c:1534
    #5  0x0000000000472bec in check_cache_items (platform=0x7fe8a0, cache=0x7fda30, ifindex=12) at platform/nm-linux-platform.c:1549
    #6  0x0000000000472de3 in announce_object (platform=0x7fe8a0, object=0x8a8c30, change_type=NM_PLATFORM_SIGNAL_REMOVED, reason=NM_PLATFORM_REASON_EXTERNAL) at platform/nm-linux-platform.c:1617
    #7  0x0000000000473dd2 in event_notification (msg=0x8a7970, user_data=0x7fe8a0) at platform/nm-linux-platform.c:1992
    #8  0x00007ffff5ee14de in nl_recvmsgs_report () from /usr/lib/libnl-3.so.200
    #9  0x00007ffff5ee1849 in nl_recvmsgs () from /usr/lib/libnl-3.so.200
    #10 0x00000000004794df in event_handler (channel=0x7fc930, io_condition=G_IO_IN, user_data=0x7fe8a0) at platform/nm-linux-platform.c:4152
    #11 0x00007ffff4c6791d in g_main_context_dispatch () from /usr/lib/libglib-2.0.so.0
    #12 0x00007ffff4c67cf8 in ?? () from /usr/lib/libglib-2.0.so.0
    #13 0x00007ffff4c68022 in g_main_loop_run () from /usr/lib/libglib-2.0.so.0
    #14 0x00000000004477ee in main (argc=1, argv=0x7fffffffeaa8) at main.c:447
    (gdb) fr 4
    #4  0x0000000000472b91 in object_has_ifindex (object=0x8a8320, ifindex=12) at platform/nm-linux-platform.c:1534
    1534                    g_assert_not_reached ();
parent dd20407c
......@@ -1725,9 +1725,15 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed
announce_object (platform, cached_object, NM_PLATFORM_SIGNAL_REMOVED, reason);
}
} else {
ObjectType type;
if (!kernel_object)
return FALSE;
/* Unsupported object types should never have reached the caches */
type = object_type_from_nl_object (kernel_object);
g_assert (type != OBJECT_TYPE_UNKNOWN);
hack_empty_master_iff_lower_up (platform, kernel_object);
if (cached_object)
......@@ -1741,7 +1747,7 @@ refresh_object (NMPlatform *platform, struct nl_object *object, gboolean removed
announce_object (platform, kernel_object, cached_object ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, reason);
/* Refresh the master device (even on enslave/release) */
if (object_type_from_nl_object (kernel_object) == OBJECT_TYPE_LINK) {
if (type == OBJECT_TYPE_LINK) {
int kernel_master = rtnl_link_get_master ((struct rtnl_link *) kernel_object);
int cached_master = cached_object ? rtnl_link_get_master ((struct rtnl_link *) cached_object) : 0;
struct nl_object *master_object;
......@@ -2003,6 +2009,11 @@ event_notification (struct nl_msg *msg, gpointer user_data)
*/
if (!kernel_object)
return NL_OK;
/* Ignore unsupported object types (e.g. AF_PHONET family addresses) */
if (type == OBJECT_TYPE_UNKNOWN)
return NL_OK;
/* Handle external addition */
if (!cached_object) {
nle = nl_cache_add (cache, kernel_object);
......@@ -4093,6 +4104,33 @@ cache_announce_changes (NMPlatform *platform, struct nl_cache *new, struct nl_ca
nl_cache_free (old);
}
/* The cache should always avoid containing objects not handled by NM, like
* e.g. addresses of the AF_PHONET family. */
static void
cache_remove_unknown (struct nl_cache *cache)
{
GPtrArray *objects_to_remove = NULL;
struct nl_object *object;
for (object = nl_cache_get_first (cache); object; object = nl_cache_get_next (object)) {
if (object_type_from_nl_object (object) == OBJECT_TYPE_UNKNOWN) {
if (!objects_to_remove)
objects_to_remove = g_ptr_array_new_with_free_func ((GDestroyNotify) nl_object_put);
nl_object_get (object);
g_ptr_array_add (objects_to_remove, object);
}
}
if (objects_to_remove) {
guint i;
for (i = 0; i < objects_to_remove->len; i++)
nl_cache_remove (g_ptr_array_index (objects_to_remove, i));
g_ptr_array_free (objects_to_remove, TRUE);
}
}
/* Creates and populates the netlink object caches. Called upon platform init and
* when we run out of sync (out of buffer space, netlink congestion control). In case
* the caches already exist, it finds changed, added and removed objects, announces
......@@ -4114,6 +4152,11 @@ cache_repopulate_all (NMPlatform *platform)
rtnl_route_alloc_cache (priv->nlh, AF_UNSPEC, 0, &priv->route_cache);
g_assert (priv->link_cache && priv->address_cache && priv->route_cache);
/* Remove all unknown objects from the caches */
cache_remove_unknown (priv->link_cache);
cache_remove_unknown (priv->address_cache);
cache_remove_unknown (priv->route_cache);
for (object = nl_cache_get_first (priv->address_cache); object; object = nl_cache_get_next (object)) {
_rtnl_addr_hack_lifetimes_rel_to_abs ((struct rtnl_addr *) object);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment