diff options
Diffstat (limited to 'libkmod')
-rw-r--r-- | libkmod/docs/libkmod-sections.txt | 2 | ||||
-rw-r--r-- | libkmod/libkmod-builtin.c | 4 | ||||
-rw-r--r-- | libkmod/libkmod-config.c | 127 | ||||
-rw-r--r-- | libkmod/libkmod-internal.h | 2 | ||||
-rw-r--r-- | libkmod/libkmod-module.c | 168 | ||||
-rw-r--r-- | libkmod/libkmod-signature.c | 6 | ||||
-rw-r--r-- | libkmod/libkmod.c | 10 | ||||
-rw-r--r-- | libkmod/libkmod.h | 5 | ||||
-rw-r--r-- | libkmod/libkmod.sym | 1 |
9 files changed, 230 insertions, 95 deletions
diff --git a/libkmod/docs/libkmod-sections.txt b/libkmod/docs/libkmod-sections.txt index e59ab7a..33d9eec 100644 --- a/libkmod/docs/libkmod-sections.txt +++ b/libkmod/docs/libkmod-sections.txt @@ -15,6 +15,7 @@ kmod_get_log_priority kmod_set_log_fn kmod_get_userdata kmod_set_userdata +kmod_get_dirname </SECTION> <SECTION> @@ -46,6 +47,7 @@ kmod_config_iter_free_iter <FILE>libkmod-module</FILE> kmod_module kmod_module_new_from_lookup +kmod_module_new_from_name_lookup kmod_module_new_from_name kmod_module_new_from_path diff --git a/libkmod/libkmod-builtin.c b/libkmod/libkmod-builtin.c index fc9a376..a002cb5 100644 --- a/libkmod/libkmod-builtin.c +++ b/libkmod/libkmod-builtin.c @@ -246,7 +246,7 @@ bool kmod_builtin_iter_get_modname(struct kmod_builtin_iter *iter, len = dot - line; - if (len > PATH_MAX) { + if (len >= PATH_MAX) { sv_errno = ENAMETOOLONG; goto fail; } @@ -313,7 +313,7 @@ ssize_t kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname, while (offset < iter->next) { offset = get_string(iter, pos, &line, &linesz); if (offset <= 0) { - count = (offset) ? -errno : -EOF; + count = (offset) ? -errno : -EINVAL; free(*modinfo); goto fail; } diff --git a/libkmod/libkmod-config.c b/libkmod/libkmod-config.c index 971f20b..e83621b 100644 --- a/libkmod/libkmod-config.c +++ b/libkmod/libkmod-config.c @@ -498,8 +498,15 @@ static int kmod_config_parse_kcmdline(struct kmod_config *config) { char buf[KCMD_LINE_SIZE]; int fd, err; - char *p, *modname, *param = NULL, *value = NULL; - bool is_quoted = false, is_module = true; + char *p, *p_quote_start, *modname, *param = NULL, *value = NULL; + bool is_quoted = false, iter = true; + enum state { + STATE_IGNORE, + STATE_MODNAME, + STATE_PARAM, + STATE_VALUE, + STATE_COMPLETE, + } state; fd = open("/proc/cmdline", O_RDONLY|O_CLOEXEC); if (fd < 0) { @@ -516,54 +523,102 @@ static int kmod_config_parse_kcmdline(struct kmod_config *config) return err; } - for (p = buf, modname = buf; *p != '\0' && *p != '\n'; p++) { - if (*p == '"') { + state = STATE_MODNAME; + p_quote_start = NULL; + for (p = buf, modname = buf; iter; p++) { + switch (*p) { + case '"': is_quoted = !is_quoted; - if (is_quoted) { - /* don't consider a module until closing quotes */ - is_module = false; - } else if (param != NULL && value != NULL) { - /* - * If we are indeed expecting a value and - * closing quotes, then this can be considered - * a valid option for a module - */ - is_module = true; + /* + * only allow starting quote as first char when looking + * for a modname: anything else is considered ill-formed + */ + if (is_quoted && state == STATE_MODNAME && p == modname) { + p_quote_start = p; + modname = p + 1; + } else if (state != STATE_VALUE) { + state = STATE_IGNORE; } - continue; - } - if (is_quoted) - continue; - - switch (*p) { + break; + case '\0': + iter = false; + /* fall-through */ case ' ': - *p = '\0'; - if (is_module) - kcmdline_parse_result(config, modname, param, value); - param = value = NULL; - modname = p + 1; - is_module = true; + case '\n': + case '\t': + case '\v': + case '\f': + case '\r': + if (is_quoted && state == STATE_VALUE) { + /* no state change*/; + } else if (is_quoted) { + /* spaces are only allowed in the value part */ + state = STATE_IGNORE; + } else if (state == STATE_VALUE || state == STATE_PARAM) { + *p = '\0'; + state = STATE_COMPLETE; + } else { + /* + * go to next option, ignoring any possible + * partial match we have + */ + modname = p + 1; + state = STATE_MODNAME; + p_quote_start = NULL; + } break; case '.': - if (param == NULL) { + if (state == STATE_MODNAME) { *p = '\0'; param = p + 1; + state = STATE_PARAM; + } else if (state == STATE_PARAM) { + state = STATE_IGNORE; } break; case '=': - if (param != NULL) + if (state == STATE_PARAM) { + /* + * Don't set *p to '\0': the value var shadows + * param + */ value = p + 1; - else - is_module = false; + state = STATE_VALUE; + } else if (state == STATE_MODNAME) { + state = STATE_IGNORE; + } break; } - } - *p = '\0'; - if (is_module) - kcmdline_parse_result(config, modname, param, value); + if (state == STATE_COMPLETE) { + /* + * We may need to re-quote to unmangle what the + * bootloader passed. Example: grub passes the option as + * "parport.dyndbg=file drivers/parport/ieee1284_ops.c +mpf" + * instead of + * parport.dyndbg="file drivers/parport/ieee1284_ops.c +mpf" + */ + if (p_quote_start && p_quote_start < modname) { + /* + * p_quote_start + * | + * |modname param value + * || | | + * vv v v + * "parport\0dyndbg=file drivers/parport/ieee1284_ops.c +mpf" */ + memmove(p_quote_start, modname, value - modname); + value--; modname--; param--; + *value = '"'; + } + kcmdline_parse_result(config, modname, param, value); + /* start over on next iteration */ + modname = p + 1; + state = STATE_MODNAME; + p_quote_start = NULL; + } + } return 0; } @@ -854,8 +909,10 @@ int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **p_config, memcpy(cf->path, path, pathlen); tmp = kmod_list_append(path_list, cf); - if (tmp == NULL) + if (tmp == NULL) { + free(cf); goto oom; + } path_list = tmp; } diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h index 398af9c..c22644a 100644 --- a/libkmod/libkmod-internal.h +++ b/libkmod/libkmod-internal.h @@ -25,10 +25,12 @@ static _always_inline_ _printf_format_(2, 3) void # else # define DBG(ctx, arg...) kmod_log_null(ctx, ## arg) # endif +# define NOTICE(ctx, arg...) kmod_log_cond(ctx, LOG_NOTICE, ## arg) # define INFO(ctx, arg...) kmod_log_cond(ctx, LOG_INFO, ## arg) # define ERR(ctx, arg...) kmod_log_cond(ctx, LOG_ERR, ## arg) #else # define DBG(ctx, arg...) kmod_log_null(ctx, ## arg) +# define NOTICE(ctx, arg...) kmod_log_null(ctx, ## arg) # define INFO(ctx, arg...) kmod_log_null(ctx, ## arg) # define ERR(ctx, arg...) kmod_log_null(ctx, ## arg) #endif diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c index 76a6dc3..12d8ed1 100644 --- a/libkmod/libkmod-module.c +++ b/libkmod/libkmod-module.c @@ -431,17 +431,18 @@ KMOD_EXPORT int kmod_module_new_from_path(struct kmod_ctx *ctx, return -EEXIST; } - *mod = kmod_module_ref(m); - return 0; - } + kmod_module_ref(m); + } else { + err = kmod_module_new(ctx, name, name, namelen, NULL, 0, &m); + if (err < 0) { + free(abspath); + return err; + } - err = kmod_module_new(ctx, name, name, namelen, NULL, 0, &m); - if (err < 0) { - free(abspath); - return err; + m->path = abspath; } - m->path = abspath; + m->builtin = KMOD_MODULE_BUILTIN_NO; *mod = m; return 0; @@ -498,13 +499,26 @@ KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod) return mod; } -#define CHECK_ERR_AND_FINISH(_err, _label_err, _list, label_finish) \ - do { \ - if ((_err) < 0) \ - goto _label_err; \ - if (*(_list) != NULL) \ - goto finish; \ - } while (0) +typedef int (*lookup_func)(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3))); + +static int __kmod_module_new_from_lookup(struct kmod_ctx *ctx, const lookup_func lookup[], + size_t lookup_count, const char *s, + struct kmod_list **list) +{ + unsigned int i; + + for (i = 0; i < lookup_count; i++) { + int err; + + err = lookup[i](ctx, s, list); + if (err < 0 && err != -ENOSYS) + return err; + else if (*list != NULL) + return 0; + } + + return 0; +} /** * kmod_module_new_from_lookup: @@ -520,7 +534,7 @@ KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod) * * The search order is: 1. aliases in configuration file; 2. module names in * modules.dep index; 3. symbol aliases in modules.symbols index; 4. aliases - * in modules.alias index. + * from install commands; 5. builtin indexes from kernel. * * The initial refcount is 1, and needs to be decremented to release the * resources of the kmod_module. The returned @list must be released by @@ -537,8 +551,17 @@ KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx, const char *given_alias, struct kmod_list **list) { - int err; + const lookup_func lookup[] = { + kmod_lookup_alias_from_config, + kmod_lookup_alias_from_moddep_file, + kmod_lookup_alias_from_symbols_file, + kmod_lookup_alias_from_commands, + kmod_lookup_alias_from_aliases_file, + kmod_lookup_alias_from_builtin_file, + kmod_lookup_alias_from_kernel_builtin_file, + }; char alias[PATH_MAX]; + int err; if (ctx == NULL || given_alias == NULL) return -ENOENT; @@ -555,46 +578,75 @@ KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx, DBG(ctx, "input alias=%s, normalized=%s\n", given_alias, alias); - /* Aliases from config file override all the others */ - err = kmod_lookup_alias_from_config(ctx, alias, list); - CHECK_ERR_AND_FINISH(err, fail, list, finish); + err = __kmod_module_new_from_lookup(ctx, lookup, ARRAY_SIZE(lookup), + alias, list); + + DBG(ctx, "lookup=%s found=%d\n", alias, err >= 0 && *list); + + if (err < 0) { + kmod_module_unref_list(*list); + *list = NULL; + } + + return err; +} + +/** + * kmod_module_new_from_name_lookup: + * @ctx: kmod library context + * @modname: module name to look for + * @mod: returned module on success + * + * Lookup by module name, without considering possible aliases. This is similar + * to kmod_module_new_from_lookup(), but don't consider as source indexes and + * configurations that work with aliases. When succesful, this always resolves + * to one and only one module. + * + * The search order is: 1. module names in modules.dep index; + * 2. builtin indexes from kernel. + * + * The initial refcount is 1, and needs to be decremented to release the + * resources of the kmod_module. Since libkmod keeps track of all + * kmod_modules created, they are all released upon @ctx destruction too. Do + * not unref @ctx before all the desired operations with the returned list are + * completed. + * + * Returns: 0 on success or < 0 otherwise. It fails if any of the lookup + * methods failed, which is basically due to memory allocation failure. If + * module is not found, it still returns 0, but @mod is left untouched. + */ +KMOD_EXPORT int kmod_module_new_from_name_lookup(struct kmod_ctx *ctx, + const char *modname, + struct kmod_module **mod) +{ + const lookup_func lookup[] = { + kmod_lookup_alias_from_moddep_file, + kmod_lookup_alias_from_builtin_file, + kmod_lookup_alias_from_kernel_builtin_file, + }; + char name_norm[PATH_MAX]; + struct kmod_list *list = NULL; + int err; + + if (ctx == NULL || modname == NULL || mod == NULL) + return -ENOENT; - DBG(ctx, "lookup modules.dep %s\n", alias); - err = kmod_lookup_alias_from_moddep_file(ctx, alias, list); - CHECK_ERR_AND_FINISH(err, fail, list, finish); + modname_normalize(modname, name_norm, NULL); - DBG(ctx, "lookup modules.symbols %s\n", alias); - err = kmod_lookup_alias_from_symbols_file(ctx, alias, list); - CHECK_ERR_AND_FINISH(err, fail, list, finish); + DBG(ctx, "input modname=%s, normalized=%s\n", modname, name_norm); - DBG(ctx, "lookup install and remove commands %s\n", alias); - err = kmod_lookup_alias_from_commands(ctx, alias, list); - CHECK_ERR_AND_FINISH(err, fail, list, finish); + err = __kmod_module_new_from_lookup(ctx, lookup, ARRAY_SIZE(lookup), + name_norm, &list); - DBG(ctx, "lookup modules.aliases %s\n", alias); - err = kmod_lookup_alias_from_aliases_file(ctx, alias, list); - CHECK_ERR_AND_FINISH(err, fail, list, finish); + DBG(ctx, "lookup=%s found=%d\n", name_norm, err >= 0 && list); - DBG(ctx, "lookup modules.builtin.modinfo %s\n", alias); - err = kmod_lookup_alias_from_kernel_builtin_file(ctx, alias, list); - if (err == -ENOSYS) { - /* Optional index missing, try the old one */ - DBG(ctx, "lookup modules.builtin %s\n", alias); - err = kmod_lookup_alias_from_builtin_file(ctx, alias, list); - } - CHECK_ERR_AND_FINISH(err, fail, list, finish); + if (err >= 0 && list != NULL) + *mod = kmod_module_get_module(list); + kmod_module_unref_list(list); -finish: - DBG(ctx, "lookup %s=%d, list=%p\n", alias, err, *list); - return err; -fail: - DBG(ctx, "Failed to lookup %s\n", alias); - kmod_module_unref_list(*list); - *list = NULL; return err; } -#undef CHECK_ERR_AND_FINISH /** * kmod_module_unref_list: @@ -771,11 +823,13 @@ extern long delete_module(const char *name, unsigned int flags); /** * kmod_module_remove_module: * @mod: kmod module - * @flags: flags to pass to Linux kernel when removing the module. The only valid flag is + * @flags: flags used when removing the module. * KMOD_REMOVE_FORCE: force remove module regardless if it's still in - * use by a kernel subsystem or other process; - * KMOD_REMOVE_NOWAIT is always enforced, causing us to pass O_NONBLOCK to + * use by a kernel subsystem or other process; passed directly to Linux kernel + * KMOD_REMOVE_NOWAIT: is always enforced, causing us to pass O_NONBLOCK to * delete_module(2). + * KMOD_REMOVE_NOLOG: when module removal fails, do not log anything as the + * caller may want to handle retries and log when appropriate. * * Remove a module from Linux kernel. * @@ -784,6 +838,8 @@ extern long delete_module(const char *name, unsigned int flags); KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod, unsigned int flags) { + unsigned int libkmod_flags = flags & 0xff; + int err; if (mod == NULL) @@ -796,7 +852,8 @@ KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod, err = delete_module(mod->name, flags); if (err != 0) { err = -errno; - ERR(mod->ctx, "could not remove '%s': %m\n", mod->name); + if (!(libkmod_flags & KMOD_REMOVE_NOLOG)) + ERR(mod->ctx, "could not remove '%s': %m\n", mod->name); } return err; @@ -2277,7 +2334,7 @@ list_error: * * After use, free the @list by calling kmod_module_info_free_list(). * - * Returns: 0 on success or < 0 otherwise. + * Returns: number of entries in @list on success or < 0 otherwise. */ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_list **list) { @@ -2912,7 +2969,10 @@ int kmod_module_get_builtin(struct kmod_ctx *ctx, struct kmod_list **list) goto fail; } - kmod_module_new_from_name(ctx, modname, &mod); + err = kmod_module_new_from_name(ctx, modname, &mod); + if (err < 0) + goto fail; + kmod_module_set_builtin(mod, true); *list = kmod_list_append(*list, mod); diff --git a/libkmod/libkmod-signature.c b/libkmod/libkmod-signature.c index 9877cf3..47aedd0 100644 --- a/libkmod/libkmod-signature.c +++ b/libkmod/libkmod-signature.c @@ -55,6 +55,7 @@ enum pkey_hash_algo { PKEY_HASH_SHA384, PKEY_HASH_SHA512, PKEY_HASH_SHA224, + PKEY_HASH_SM3, PKEY_HASH__LAST }; @@ -67,6 +68,7 @@ const char *const pkey_hash_algo[PKEY_HASH__LAST] = { [PKEY_HASH_SHA384] = "sha384", [PKEY_HASH_SHA512] = "sha512", [PKEY_HASH_SHA224] = "sha224", + [PKEY_HASH_SM3] = "sm3", }; enum pkey_id_type { @@ -160,6 +162,10 @@ static int obj_to_hash_algo(const ASN1_OBJECT *o) return PKEY_HASH_SHA512; case NID_sha224: return PKEY_HASH_SHA224; +# ifndef OPENSSL_NO_SM3 + case NID_sm3: + return PKEY_HASH_SM3; +# endif default: return -1; } diff --git a/libkmod/libkmod.c b/libkmod/libkmod.c index 43423d6..7c2b889 100644 --- a/libkmod/libkmod.c +++ b/libkmod/libkmod.c @@ -64,6 +64,7 @@ static struct _index_files { static const char *default_config_paths[] = { SYSCONFDIR "/modprobe.d", "/run/modprobe.d", + "/usr/local/lib/modprobe.d", "/lib/modprobe.d", NULL }; @@ -234,10 +235,11 @@ static char *get_kernel_release(const char *dirname) * Otherwise, give an absolute dirname. * @config_paths: ordered array of paths (directories or files) where * to load from user-defined configuration parameters such as - * alias, blacklists, commands (install, remove). If - * NULL defaults to /run/modprobe.d, /etc/modprobe.d and - * /lib/modprobe.d. Give an empty vector if configuration should - * not be read. This array must be null terminated. + * alias, blacklists, commands (install, remove). If NULL + * defaults to /etc/modprobe.d, /run/modprobe.d, + * /usr/local/lib/modprobe.d and /lib/modprobe.d. Give an empty + * vector if configuration should not be read. This array must + * be null terminated. * * Create kmod library context. This reads the kmod configuration * and fills in the default values. diff --git a/libkmod/libkmod.h b/libkmod/libkmod.h index 3cab2e5..7251aa7 100644 --- a/libkmod/libkmod.h +++ b/libkmod/libkmod.h @@ -129,6 +129,9 @@ int kmod_module_new_from_path(struct kmod_ctx *ctx, const char *path, struct kmod_module **mod); int kmod_module_new_from_lookup(struct kmod_ctx *ctx, const char *given_alias, struct kmod_list **list); +int kmod_module_new_from_name_lookup(struct kmod_ctx *ctx, + const char *modname, + struct kmod_module **mod); int kmod_module_new_from_loaded(struct kmod_ctx *ctx, struct kmod_list **list); @@ -142,6 +145,8 @@ struct kmod_module *kmod_module_get_module(const struct kmod_list *entry); enum kmod_remove { KMOD_REMOVE_FORCE = O_TRUNC, KMOD_REMOVE_NOWAIT = O_NONBLOCK, /* always set */ + /* libkmod-only defines, not passed to kernel */ + KMOD_REMOVE_NOLOG = 1, }; /* Insertion flags */ diff --git a/libkmod/libkmod.sym b/libkmod/libkmod.sym index 5f5e1fb..0c04fda 100644 --- a/libkmod/libkmod.sym +++ b/libkmod/libkmod.sym @@ -30,6 +30,7 @@ global: kmod_module_new_from_name; kmod_module_new_from_path; kmod_module_new_from_lookup; + kmod_module_new_from_name_lookup; kmod_module_new_from_loaded; kmod_module_ref; kmod_module_unref; |