mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-24 23:00:07 +01:00
core: check file permissions when loading device plugins and order by file modification time
Refactor the loading of device plugins by creating the list of module filenames in a separate function. Thereby also check for file permissions (must be only modifiable by root) and sort the files by last file modification time. This has the advantage, that if several plugins provide the same device type, that we (deterministically) prefer the most recent one. Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
parent
baab3cc641
commit
05e2e701a8
1 changed files with 93 additions and 19 deletions
112
src/nm-manager.c
112
src/nm-manager.c
|
|
@ -1879,42 +1879,116 @@ factory_component_added_cb (NMDeviceFactory *factory,
|
|||
#define PLUGIN_PATH_TAG "NMManager-plugin-path"
|
||||
#define PLUGIN_TYPEFUNC_TAG "typefunc"
|
||||
|
||||
static void
|
||||
load_device_factories (NMManager *self)
|
||||
struct read_device_factory_paths_data {
|
||||
char *path;
|
||||
struct stat st;
|
||||
};
|
||||
|
||||
static gint
|
||||
read_device_factory_paths_sort_fcn (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
const struct read_device_factory_paths_data *da = a;
|
||||
const struct read_device_factory_paths_data *db = b;
|
||||
time_t ta, tb;
|
||||
|
||||
ta = MAX (da->st.st_mtime, da->st.st_ctime);
|
||||
tb = MAX (db->st.st_mtime, db->st.st_ctime);
|
||||
|
||||
if (ta < tb)
|
||||
return 1;
|
||||
if (ta > tb)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static char**
|
||||
read_device_factory_paths ()
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
GDir *dir;
|
||||
GError *error = NULL;
|
||||
const char *item;
|
||||
char *path;
|
||||
GSList *iter;
|
||||
GArray *paths;
|
||||
char **result;
|
||||
guint i;
|
||||
|
||||
dir = g_dir_open (NMPLUGINDIR, 0, &error);
|
||||
if (!dir) {
|
||||
nm_log_warn (LOGD_HW, "Failed to open plugin directory %s: %s",
|
||||
nm_log_warn (LOGD_HW, "device plugin: failed to open directory %s: %s",
|
||||
NMPLUGINDIR,
|
||||
(error && error->message) ? error->message : "(unknown)");
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
paths = g_array_new (FALSE, FALSE, sizeof (struct read_device_factory_paths_data));
|
||||
|
||||
while ((item = g_dir_read_name (dir))) {
|
||||
GModule *plugin;
|
||||
NMDeviceFactory *factory;
|
||||
NMDeviceFactoryCreateFunc create_func;
|
||||
NMDeviceFactoryDeviceTypeFunc type_func;
|
||||
NMDeviceType dev_type;
|
||||
const char *found = NULL;
|
||||
struct read_device_factory_paths_data data;
|
||||
|
||||
if (!g_str_has_prefix (item, PLUGIN_PREFIX))
|
||||
continue;
|
||||
if (g_str_has_suffix (item, ".la"))
|
||||
continue;
|
||||
|
||||
path = g_module_build_path (NMPLUGINDIR, item);
|
||||
g_assert (path);
|
||||
plugin = g_module_open (path, G_MODULE_BIND_LOCAL);
|
||||
g_free (path);
|
||||
data.path = g_build_filename (NMPLUGINDIR, item, NULL);
|
||||
|
||||
if (stat (data.path, &data.st) != 0)
|
||||
goto continue_with_error;
|
||||
if (!S_ISREG (data.st.st_mode))
|
||||
goto continue_silently;
|
||||
if (data.st.st_uid != 0)
|
||||
goto continue_with_error;
|
||||
if (data.st.st_mode & (S_IWGRP | S_IWOTH | S_ISUID))
|
||||
goto continue_with_error;
|
||||
|
||||
g_array_append_val (paths, data);
|
||||
continue;
|
||||
|
||||
continue_with_error:
|
||||
nm_log_dbg (LOGD_HW, "device plugin: skip invalid file %s", data.path);
|
||||
continue_silently:
|
||||
g_free (data.path);
|
||||
}
|
||||
g_dir_close (dir);
|
||||
|
||||
/* sort filenames by modification time. */
|
||||
g_array_sort (paths, read_device_factory_paths_sort_fcn);
|
||||
|
||||
result = g_new (char *, paths->len + 1);
|
||||
for (i = 0; i < paths->len; i++)
|
||||
result[i] = g_array_index (paths, struct read_device_factory_paths_data, i).path;
|
||||
result[i] = NULL;
|
||||
|
||||
g_array_free (paths, TRUE);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
load_device_factories (NMManager *self)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
char **path;
|
||||
char **paths;
|
||||
|
||||
paths = read_device_factory_paths ();
|
||||
if (!paths)
|
||||
return;
|
||||
|
||||
for (path = paths; *path; path++) {
|
||||
GError *error = NULL;
|
||||
GModule *plugin;
|
||||
NMDeviceFactory *factory;
|
||||
NMDeviceFactoryCreateFunc create_func;
|
||||
NMDeviceFactoryDeviceTypeFunc type_func;
|
||||
NMDeviceType dev_type;
|
||||
const char *found = NULL;
|
||||
GSList *iter;
|
||||
const char *item;
|
||||
|
||||
item = strrchr (*path, '/');
|
||||
g_assert (item);
|
||||
|
||||
plugin = g_module_open (*path, G_MODULE_BIND_LOCAL);
|
||||
|
||||
if (!plugin) {
|
||||
nm_log_warn (LOGD_HW, "(%s): failed to load plugin: %s", item, g_module_error ());
|
||||
|
|
@ -1939,7 +2013,7 @@ load_device_factories (NMManager *self)
|
|||
}
|
||||
}
|
||||
if (found) {
|
||||
nm_log_warn (LOGD_HW, "Found multiple device plugins for same type: %s vs %s",
|
||||
nm_log_warn (LOGD_HW, "Found multiple device plugins for same type: use '%s' instead of '%s'",
|
||||
found, g_module_name (plugin));
|
||||
g_module_close (plugin);
|
||||
continue;
|
||||
|
|
@ -1978,7 +2052,7 @@ load_device_factories (NMManager *self)
|
|||
|
||||
nm_log_info (LOGD_HW, "Loaded device plugin: %s", g_module_name (plugin));
|
||||
};
|
||||
g_dir_close (dir);
|
||||
g_strfreev (paths);
|
||||
|
||||
priv->factories = g_slist_reverse (priv->factories);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue