We often want to cascade hashing, meaning, to combine the
outcome of various hash functions in a larger hash.
Instead of having each hash function return a guint hash value,
accept a hash state argument. This saves the overhead of initializing
and completing the intermediate hash states.
It also avoids loosing entropy when we reduce the larger hash state
into the intermediate guint hash value.
By using a macro, we don't cast all the types to guint. Instead,
we use their native types directly. Hence, we don't need
nm_hash_update_uint64() nor nm_hash_update_ptr().
Also, for types smaller then guint like char, we save hashing
the all zero bytes.
siphash24() is wildly used by projects nowadays.
It's certainly slower then our djb hashing that we used before.
But quite likely it's fast enough for us, given how wildly it is
used. I think it would be hard to profile NetworkManager to show
that the performance of hash tables is the issue, be it with
djb or siphash24.
Certainly with siphash24() it's much harder to exploit the hashing
algorithm to cause worst case hash operations (provided that the
seed is kept private). Does this better resistance against a denial
of service matter for us? Probably not, but let's better be safe then
sorry.
Note that systemd's implementation uses a different seed for each hash
table (at least, after the hash table grows to a certain size).
We don't do that and use only one global seed.
Replace the usage of g_str_hash() with our own nm_str_hash().
GLib's g_str_hash() uses djb2 hashing function, just like we
do at the moment. The only difference is, that we use a diffrent
seed value.
Note, that we initialize the hash seed with random data (by calling
getrandom() or reading /dev/urandom). That is a change compared to
before.
This change of the hashing function and accessing the random pool
might be undesired for libnm/libnm-core. Hence, the change is not
done there as it possibly changes behavior for public API. Maybe
we should do that later though.
At this point, there isn't much of a change. This patch becomes
interesting, if we decide to use a different hashing algorithm.
The privious NM_HASH_* macros directly operated on a guint value
and were thus close to the actual implementation.
Replace them by adding a NMHashState struct and accessors to
update the hash state. This hides the implementation better
and would allow us to carry more state. For example, we could
switch to siphash24() transparently.
For now, we still do a form basically djb2 hashing, albeit with
differing start seed.
Also add nm_hash_str() and nm_str_hash():
- nm_hash_str() is our own string hashing implementation
- nm_str_hash() is our own string implementation, but with a
GHashFunc signature, suitable to pass it to g_hash_table_new().
Also, it has this name in order to remind you of g_str_hash(),
which it is replacing.
"nm-utils/nm-shared-utils.h" shall contain utility function without other
dependencies. It is intended to be used by other projects as-is.
nm_utils_random_bytes() requires getrandom() and a HAVE_GETRANDOM configure
check. That makes it more cumbersome to re-use "nm-shared-utils.h", in
cases where you don't care about nm_utils_random_bytes().
Split nm_utils_random_bytes() out to a separate file.
Same for hash utils, which depend on nm_utils_random_bytes(). Also, hash
utils will eventually be extended to use siphash24.
==28576== 78 (72 direct, 6 indirect) bytes in 1 blocks are definitely lost in loss record 843 of 1,311
==28576== at 0x4C2EB6B: malloc (vg_replace_malloc.c:299)
==28576== by 0x6FD0A38: g_malloc (gmem.c:94)
==28576== by 0x6FE8575: g_slice_alloc (gslice.c:1025)
==28576== by 0x6FE8A08: g_slice_alloc0 (gslice.c:1051)
==28576== by 0x7010261: g_system_thread_new (gthread-posix.c:1152)
==28576== by 0x6FF283E: g_thread_new_internal (gthread.c:874)
==28576== by 0x6FF28E7: g_thread_new (gthread.c:827)
==28576== by 0x6FCC4A3: g_get_worker_context (gmain.c:5851)
==28576== by 0x681A814: g_task_thread_pool_init (gtask.c:1977)
==28576== by 0x681A814: g_task_get_type (gtask.c:592)
==28576== by 0x685CB50: ensure_required_types (gdbusprivate.c:231)
==28576== by 0x685CB50: _g_dbus_initialize (gdbusprivate.c:1927)
==28576== by 0x6850CA0: g_bus_get_sync (gdbusconnection.c:7267)
==28576== by 0x10B6AC: nmtstc_service_init (nm-test-utils-impl.c:91)
==28576== by 0x10D261: test_setup (test-secret-agent.c:249)
==28576== by 0x6FF118B: test_case_run (gtestutils.c:2160)
==28576== by 0x6FF118B: g_test_run_suite_internal (gtestutils.c:2244)
==28576== by 0x6FF139A: g_test_run_suite_internal (gtestutils.c:2256)
==28576== by 0x6FF139A: g_test_run_suite_internal (gtestutils.c:2256)
==28576== by 0x6FF1571: g_test_run_suite (gtestutils.c:2332)
==28576== by 0x6FF1590: g_test_run (gtestutils.c:1599)
==28576== by 0x10D0EE: main (test-secret-agent.c:654)
nmtui determines the activation result by tracking the active
connection state but that is not enough, as the active connection may
disappear or because we need to consider also the device state in some
particular cases.
Use the same logic implemented in nmcli that is now provided by the
nmc_activation_get_effective_state() helper.
In a later commit we'll add a new generic client function used by
nmcli and nmtui. nm-client-utils.c seems the right place for it, so
move the file to the base library that is used by both clients.
While at it, also put in that file some functions that will be needed
by nmtui.
This makes hashing non-deterministic with the aim to
make it harder to exploit hash collisions.
Non-deterministic also means that for unit testing
we will get different values on each run. But since we
shall never assign any meaning to these hash values
nor rely on them being stable between restarts (or
upgrades), that doesn't hurt.
Introduce a NM_HASH_INIT() function. It makes the places
where we initialize a hash with a certain seed visually clear.
Also, move them from "shared/nm-utils/nm-shared-utils.h" to
"shared/nm-utils/nm-macros-internal.h". We might want to
have NM_HASH_INIT() non-inline (hence, define it in the
source file).
Add a new function nm_utils_random_bytes().
This function now preferably uses getrandom() syscall if it is
available.
As fallback, it always tries to fill the buffer from /dev/urandom.
If it cannot, as last fallback it uses GRand, which cannot fail.
Hence, the function always sets some (pseudo) random bytes.
It also returns FALSE if the obtained bytes are possibly not good
randomness.
Fixes the following:
shared/nm-utils/nm-shared-utils.c:136: Warning: NetworkManager: GTK-Doc comment block end token "*/" should not be preceded by comment text:
* Returns: the input buffer with the quoted string. */
So that the man page will display:
The permitted values are: NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64
(0) or NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_STABLE_PRIVACY (1).
instead of
The permitted values are: "eui64" or "stable-privacy".
since the latter is not useful at all for a int32 property.
Unfortunately the enum names are quite long and don't look very well
in a table, but that's another problem.
For routes and the default-route from NDisc, set the router preference
RTA_PREF.
Also, previously, we would only configure one IPv6 default-route. That by itself
was not really a problem, as long as NetworkManager would always make sure that
it configured the route to the ~best~ router.
Actually, NM should have done that already. It keeps the list of gateways
sorted, and prefers them according to their preference. But maybe
it didn't, so we have bug rh#1445417 (??).
Change that by configuring a default-route for all gateways, with
appropriate router prefrence. In case, kernel doesn't support RTA_PREF
yet, only configure all routes that share the same maxiumum preference.
https://bugzilla.redhat.com/show_bug.cgi?id=1445417
- add assert code to check that our internal tracking of
the gateways is consistent.
- assert (gracefully) against libndp returning :: as gateway
address.
We encounter the same enum in 3 forms:
- NMNDiscPreference in NetworkManager
- "enum ndp_route_preference" in <ndp.h>
- ICMPV6_ROUTER_PREF_* in <linux/icmpv6.h>
Move our enum to nm-core-utils.h, so that it can be used
by platform code as well (platform code should not include
ndisc/nm-ndisc.h).
Also, NMNDiscPreference was not numerically identical to their
native values (meaning: it shuffled the names and numbers).
Make them all numerically equal, so that they can be used in
the same context.
This means, while previously we could compare NMNDiscPreference
directly according to their priority, we now need _preference_to_priority().
On the other hand, we could omit translate_preference() -- but actually,
we still have _route_preference_coerce() because pref comes from libndp
and is thus untrusted. We still have to range check it.
We have the timestamp nm_utils_get_monotonic_time_s(), which should be
gint32 type. Then we also have timestamps in the NMNDisc* objects, which
consist of guint32 timestamp and lifetime.
Cleanup handling the times and calculation of the timestamps by using
the correct integer type consistently and ensuring that no integer overflow
occurs.
The @i variable to loop over the arrays should have the same type as
GArray.len, to which it is compared. In this case "guint".
As we remove items from the arrays while iterating over it, it gets
a bit complicated either way. I disliked that
g_array_remove_index (rdata->gateways, i--);
would underflow for unsigned integers. While that would work fine,
I think that is confusing. So, the variable is no longer incremented
in the increment statement of the for loop.
The bus manager takes extra references to the GDBusConnection every
time g_dbus_object_manager_server_get_connection() its called,
preventing its disposal once the connection is closed. This causes a
leak for each DHCP event.
https://bugzilla.redhat.com/show_bug.cgi?id=1461643
When adding a new Wi-Fi connection, nmtui crashes.
Usually, a verified Wi-Fi connection always has key_mgnt set.
However, the client doesn't have the luxury to assume that all
connections verify. Especially, while creating a new connection.
#0 0x00007ffff4fe5baa in __strcmp_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S:31
#1 0x000055555556654c in get_security_type (binding=0x5555557d1cf0) at clients/tui/nm-editor-bindings.c:591
#2 0x000055555556593b in wireless_security_changed (object=0x0, pspec=0x0, user_data=0x5555557d1cf0) at clients/tui/nm-editor-bindings.c:628
#3 0x000055555556536d in nm_editor_bind_wireless_security_method (connection=0x5555558028e0, s_wsec=0x555555892eb0 [NMSettingWirelessSecurity], target=0x555555935e10, target_property=0x55555559311b "active-id", flags=(G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE)) at clients/tui/nm-editor-bindings.c:796
#4 0x000055555557a3aa in nmt_page_wifi_constructed (object=0x5555559349e0 [NmtPageWifi]) at clients/tui/nmt-page-wifi.c:338
#5 0x00007ffff5e6b670 in g_object_new_internal (class=class@entry=0x5555557c14c0, params=params@entry=0x7fffffffc440, n_params=n_params@entry=2) at gobject.c:1823
#6 0x00007ffff5e6d24d in g_object_new_valist (object_type=object_type@entry=93824994775616, first_property_name=first_property_name@entry=0x5555555920c6 "connection", var_args=var_args@entry=0x7fffffffc590) at gobject.c:2042
#7 0x00007ffff5e6d691 in g_object_new (object_type=93824994775616, first_property_name=0x5555555920c6 "connection") at gobject.c:1626
#8 0x000055555557985a in nmt_page_wifi_new (conn=0x5555558028e0, deventry=0x5555557d15e0 [NmtDeviceEntry]) at clients/tui/nmt-page-wifi.c:45
#9 0x000055555556f7e2 in nmt_editor_constructed (object=0x555555922af0 [NmtEditor]) at clients/tui/nmt-editor.c:374
#10 0x00007ffff5e6b670 in g_object_new_internal (class=class@entry=0x555555932750, params=params@entry=0x7fffffffcac0, n_params=n_params@entry=4) at gobject.c:1823
#11 0x00007ffff5e6d24d in g_object_new_valist (object_type=object_type@entry=93824996288016, first_property_name=first_property_name@entry=0x5555555920c6 "connection", var_args=var_args@entry=0x7fffffffcc10) at gobject.c:2042
#12 0x00007ffff5e6d691 in g_object_new (object_type=93824996288016, first_property_name=0x5555555920c6 "connection") at gobject.c:1626
#13 0x000055555556f261 in nmt_editor_new (connection=0x555555802880) at clients/tui/nmt-editor.c:109
#14 0x0000555555562b35 in nmt_edit_connection (connection=0x555555802880) at clients/tui/nmtui-edit.c:448
#15 0x0000555555563a29 in create_connection (widget=0x55555588b150 [NmtNewtListbox], list=0x555555922a00) at clients/tui/nmtui-edit.c:185
#16 0x0000555555563a5d in create_connection_and_quit (widget=0x55555588b150 [NmtNewtListbox], list=0x555555922a00) at clients/tui/nmtui-edit.c:192
#20 0x00007ffff5e81b0f in <emit signal ??? on instance 0x55555588b150 [NmtNewtListbox]> (instance=<optimized out>, signal_id=<optimized out>, detail=<optimized out>) at gsignal.c:3447
#17 0x00007ffff5e6630d in g_closure_invoke (closure=0x555555929260, return_value=0x0, n_param_values=1, param_values=0x7fffffffcfe0, invocation_hint=0x7fffffffcf60) at gclosure.c:804
#18 0x00007ffff5e7898e in signal_emit_unlocked_R (node=node@entry=0x55555582ac70, detail=detail@entry=0, instance=instance@entry=0x55555588b150, emission_return=emission_return@entry=0x0, instance_and_params=instance_and_params@entry=0x7fffffffcfe0) at gsignal.c:3635
#19 0x00007ffff5e811a5 in g_signal_emit_valist (instance=0x55555588b150, signal_id=<optimized out>, detail=0, var_args=var_args@entry=0x7fffffffd1b0) at gsignal.c:3391
#21 0x000055555558e43f in nmt_newt_widget_activated (widget=0x55555588b150 [NmtNewtListbox]) at clients/tui/newt/nmt-newt-widget.c:329
#22 0x0000555555584fc8 in nmt_newt_form_iterate (form=0x555555922a00 [NmtAddConnection]) at clients/tui/newt/nmt-newt-form.c:309
#23 0x0000555555585d62 in nmt_newt_form_keypress_callback (fd=1435623072, condition=G_IO_IN, user_data=0x0) at clients/tui/newt/nmt-newt-form.c:335
#24 0x00007ffff598a247 in g_main_dispatch (context=0x5555557c3af0) at gmain.c:3234
#25 0x00007ffff598a247 in g_main_context_dispatch (context=context@entry=0x5555557c3af0) at gmain.c:3899
#26 0x00007ffff598a5e8 in g_main_context_iterate (context=0x5555557c3af0, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3972
#27 0x00007ffff598a902 in g_main_loop_run (loop=0x55555591b190) at gmain.c:4168
#28 0x00005555555609b5 in main (argc=1, argv=0x7fffffffd5e8) at clients/tui/nmtui.c:298
Fixes: 6a4af482f0
Before commit 650a7022c1, we would
always forego using getrandom(). That changed, and now we detect
at compile time whether getrandom() is provided by libc. So, if you
build against recent libc, we use it too.
However, systemd's src/basic/missing_syscall.h also provides getrandom() by
calling the syscall directly. We don't do that, because it seems too cumbersome
to maintain.
Fixes: 650a7022c1
Extend policy-routing and replace previously added route-table-sync
setting with a route-table setting. The route table can now be
configured per connection profile and affects all routes.
This branch breaks API/ABI on development branch by dropping
ipv4.route-table-sync from libnm.
https://bugzilla.redhat.com/show_bug.cgi?id=1436531
Instead of having 3 properties @gateway, @never_default and @has_gateway
on NMIP4Config/NMIP6Config that determine the default-route, track the
default-route as a regular route.
The gateway setting is the configuration knob for the default-route.
Since an NMIP4Config/NMIP6Config instance only has one gateway property,
it cannot track more then one default-routes (see related bug rh#1445417).
Especially with policy routing, it might be interesting to configure a
default-route in multiple tables.
Also, later it might be interesting to allow adding default-routes as
regular static routes in a connection, so that the user can configure additional
route parameters for the default-route or add default-routes in multiple tables.
With this patch, default-routes now have a rt_source property according to their
origin.
Also, the previous commits of this branch broke handling of the
default-route :) . That should be working now again.
It's not needed. Whenever we add a route, we pass in the
route metric (for example, based on the device's configuration).
No need to merge and track it into the NMIP4Config/NMIP6Config.
The metric was only used in nm_ip4_config_create_setting()
and nm_ip6_config_create_setting(). In fact it's wrong to do
that, because it means we first capture some settings, and guess
the configured route metric. But we cannot do that. Our best
guess what a configured setting might be is -1.
The MSS is only set for VPN connections (by merging it in the respective
NMIP4Config/NMIP6Config).
It is also only used when setting the MSS of the default route.
Don't track that property in NMIP4Config/NMIP6Config, instead, set the
mss of the route directly in nm_vpn_connection_ip4_config_get() and
nm_vpn_connection_ip6_config_get().
There is a potential change in behavior here: NMDevice also consisdered
the MSS for the default route, but that would only be set if the MSS
gets merged from an vpn-ip-config. Which at most is the case for
iterface-less VPN types (libreswan). But even in that case, it doesn't
seem right to me to use the VPN's MSS for the device's default-route.