Skip to content

Commit 10935bf

Browse files
osuchowskijslepeck
authored andcommitted
libkmod: add mask command
Mask command prevents modules from loading. It intends to be a strict and intent-based replacement for variations of install and blacklist commands, for example: * install module /bin/false * install module /bin/true * blacklist module, with modprobe -b This commit is a pure extension and the already established behaviour is not expected to change as a result. Closes: #440 Closes: #40 Co-authored-by: Jakub Ślepecki <jakub.slepecki@intel.com> Signed-off-by: Jakub Ślepecki <jakub.slepecki@intel.com> Signed-off-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com>
1 parent d233b24 commit 10935bf

35 files changed

Lines changed: 233 additions & 8 deletions

libkmod/docs/libkmod-docs.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,8 @@
6060
<title>Index of new symbols in 33</title>
6161
<xi:include href="xml/api-index-33.xml"></xi:include>
6262
</chapter>
63+
<chapter id="api-index-v35" role="35">
64+
<title>Index of new symbols in 35</title>
65+
<xi:include href="xml/api-index-35.xml"></xi:include>
66+
</chapter>
6367
</book>

libkmod/docs/libkmod-sections.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ kmod_list_prev
3535
kmod_config_iter
3636
kmod_config_get_blacklists
3737
kmod_config_get_install_commands
38+
kmod_config_get_masks
3839
kmod_config_get_remove_commands
3940
kmod_config_get_aliases
4041
kmod_config_get_options

libkmod/libkmod-config.c

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ struct kmod_weakdep {
5151
unsigned int n_weak;
5252
};
5353

54+
const char *kmod_mask_get_modname(const struct kmod_list *l)
55+
{
56+
return l->data;
57+
}
58+
5459
const char *kmod_blacklist_get_modname(const struct kmod_list *l)
5560
{
5661
return l->data;
@@ -232,6 +237,27 @@ static int kmod_config_add_blacklist(struct kmod_config *config, const char *mod
232237
return 0;
233238
}
234239

240+
static int kmod_config_add_mask(struct kmod_config *config, const char *modname)
241+
{
242+
_cleanup_free_ char *p;
243+
struct kmod_list *list;
244+
245+
DBG(config->ctx, "modname=%s\n", modname);
246+
247+
_clang_suppress_alloc_ p = strdup(modname);
248+
if (!p)
249+
return -ENOMEM;
250+
251+
list = kmod_list_append(config->masks, p);
252+
if (!list)
253+
return -ENOMEM;
254+
255+
TAKE_PTR(p);
256+
config->masks = list;
257+
258+
return 0;
259+
}
260+
235261
static int kmod_config_add_softdep(struct kmod_config *config, const char *modname,
236262
const char *line)
237263
{
@@ -607,12 +633,15 @@ static char *weakdep_to_char(struct kmod_weakdep *dep)
607633
static void kcmdline_parse_result(struct kmod_config *config, char *modname, char *param,
608634
char *value)
609635
{
636+
bool is_blacklist, is_mask;
610637
if (modname == NULL || param == NULL)
611638
return;
612639

613640
DBG(config->ctx, "%s %s\n", modname, param);
614641

615-
if (streq(modname, "modprobe") && strstartswith(param, "blacklist=")) {
642+
is_blacklist = strstartswith(param, "blacklist=");
643+
is_mask = strstartswith(param, "mask=");
644+
if (streq(modname, "modprobe") && (is_blacklist || is_mask)) {
616645
for (;;) {
617646
char *t = strsep(&value, ",");
618647
if (t == NULL)
@@ -621,7 +650,10 @@ static void kcmdline_parse_result(struct kmod_config *config, char *modname, cha
621650
if (underscores(t) < 0)
622651
continue;
623652

624-
kmod_config_add_blacklist(config, t);
653+
if (is_blacklist)
654+
kmod_config_add_blacklist(config, t);
655+
else
656+
kmod_config_add_mask(config, t);
625657
}
626658
} else {
627659
if (underscores(modname) < 0) {
@@ -827,6 +859,13 @@ static int kmod_config_parse(struct kmod_config *config, int fd, const char *fil
827859

828860
kmod_config_add_command(config, modname, installcmd, cmd,
829861
&config->install_commands);
862+
} else if (streq(cmd, "mask")) {
863+
char *modname = strtok_r(NULL, "\t ", &saveptr);
864+
865+
if (underscores(modname) < 0)
866+
goto syntax_error;
867+
868+
kmod_config_add_mask(config, modname);
830869
} else if (streq(cmd, "remove")) {
831870
char *modname = strtok_r(NULL, "\t ", &saveptr);
832871
char *removecmd = strtok_r(NULL, "\0", &saveptr);
@@ -876,6 +915,7 @@ void kmod_config_free(struct kmod_config *config)
876915
kmod_list_release(config->blacklists, free);
877916
kmod_list_release(config->options, free);
878917
kmod_list_release(config->install_commands, free);
918+
kmod_list_release(config->masks, free);
879919
kmod_list_release(config->remove_commands, free);
880920
kmod_list_release(config->softdeps, free);
881921
kmod_list_release(config->weakdeps, free);
@@ -1098,6 +1138,7 @@ int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **p_config,
10981138
enum config_type {
10991139
CONFIG_TYPE_BLACKLIST = 0,
11001140
CONFIG_TYPE_INSTALL,
1141+
CONFIG_TYPE_MASK,
11011142
CONFIG_TYPE_REMOVE,
11021143
CONFIG_TYPE_ALIAS,
11031144
CONFIG_TYPE_OPTION,
@@ -1148,6 +1189,10 @@ static struct kmod_config_iter *kmod_config_iter_new(const struct kmod_ctx *ctx,
11481189
iter->get_key = kmod_command_get_modname;
11491190
iter->get_value = kmod_command_get_command;
11501191
break;
1192+
case CONFIG_TYPE_MASK:
1193+
iter->list = config->masks;
1194+
iter->get_key = kmod_mask_get_modname;
1195+
break;
11511196
case CONFIG_TYPE_REMOVE:
11521197
iter->list = config->remove_commands;
11531198
iter->get_key = kmod_command_get_modname;
@@ -1198,6 +1243,14 @@ KMOD_EXPORT struct kmod_config_iter *kmod_config_get_install_commands(const stru
11981243
return kmod_config_iter_new(ctx, CONFIG_TYPE_INSTALL);
11991244
}
12001245

1246+
KMOD_EXPORT struct kmod_config_iter *kmod_config_get_masks(const struct kmod_ctx *ctx)
1247+
{
1248+
if (ctx == NULL)
1249+
return NULL;
1250+
1251+
return kmod_config_iter_new(ctx, CONFIG_TYPE_MASK);
1252+
}
1253+
12011254
// clang-format off
12021255
KMOD_EXPORT struct kmod_config_iter *kmod_config_get_remove_commands(const struct kmod_ctx *ctx)
12031256
// clang-format on

libkmod/libkmod-internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ struct kmod_config {
9999
struct kmod_list *aliases;
100100
struct kmod_list *blacklists;
101101
struct kmod_list *options;
102+
struct kmod_list *masks;
102103
struct kmod_list *remove_commands;
103104
struct kmod_list *install_commands;
104105
struct kmod_list *softdeps;
@@ -112,6 +113,7 @@ _nonnull_all_ void kmod_config_free(struct kmod_config *config);
112113
_nonnull_all_ const char *kmod_blacklist_get_modname(const struct kmod_list *l);
113114
_nonnull_all_ const char *kmod_alias_get_name(const struct kmod_list *l);
114115
_nonnull_all_ const char *kmod_alias_get_modname(const struct kmod_list *l);
116+
_nonnull_all_ const char *kmod_mask_get_modname(const struct kmod_list *l);
115117
_nonnull_all_ const char *kmod_option_get_options(const struct kmod_list *l);
116118
_nonnull_all_ const char *kmod_option_get_modname(const struct kmod_list *l);
117119
_nonnull_all_ const char *kmod_command_get_command(const struct kmod_list *l);

libkmod/libkmod-module.c

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -737,12 +737,30 @@ static bool module_is_blacklisted(const struct kmod_module *mod)
737737
return false;
738738
}
739739

740+
static bool module_is_masked(const struct kmod_module *mod)
741+
{
742+
const struct kmod_ctx *ctx = mod->ctx;
743+
const struct kmod_config *config = kmod_get_config(ctx);
744+
const struct kmod_list *bl = config->masks;
745+
const struct kmod_list *l;
746+
747+
kmod_list_foreach(l, bl) {
748+
const char *modname = kmod_mask_get_modname(l);
749+
750+
if (streq(modname, mod->name))
751+
return true;
752+
}
753+
754+
return false;
755+
}
756+
740757
KMOD_EXPORT int kmod_module_apply_filter(const struct kmod_ctx *ctx,
741758
enum kmod_filter filter_type,
742759
const struct kmod_list *input,
743760
struct kmod_list **output)
744761
{
745762
const struct kmod_list *li;
763+
int err = 0;
746764

747765
if (ctx == NULL || output == NULL)
748766
return -ENOENT;
@@ -761,9 +779,20 @@ KMOD_EXPORT int kmod_module_apply_filter(const struct kmod_ctx *ctx,
761779
if ((filter_type & KMOD_FILTER_BUILTIN) && kmod_module_is_builtin(mod))
762780
continue;
763781

782+
if ((filter_type & KMOD_FILTER_MASK) && module_is_masked(mod)) {
783+
if (!mod->required)
784+
continue;
785+
ERR(mod->ctx, "module is masked: %s\n",
786+
kmod_module_get_name(mod));
787+
err = -EINVAL;
788+
goto fail;
789+
}
790+
764791
node = kmod_list_append(*output, mod);
765-
if (node == NULL)
792+
if (node == NULL) {
793+
err = -ENOMEM;
766794
goto fail;
795+
}
767796

768797
*output = node;
769798
kmod_module_ref(mod);
@@ -774,7 +803,7 @@ KMOD_EXPORT int kmod_module_apply_filter(const struct kmod_ctx *ctx,
774803
fail:
775804
kmod_module_unref_list(*output);
776805
*output = NULL;
777-
return -ENOMEM;
806+
return err;
778807
}
779808

780809
static int command_do(struct kmod_module *mod, const char *type, const char *cmd)
@@ -1008,7 +1037,7 @@ KMOD_EXPORT int kmod_module_probe_insert_module(
10081037
const void *data,
10091038
void (*print_action)(struct kmod_module *m, bool install, const char *options))
10101039
{
1011-
struct kmod_list *list = NULL, *l;
1040+
struct kmod_list *list = NULL, *l, *filtered = NULL;
10121041
struct probe_insert_cb cb;
10131042
int err;
10141043

@@ -1022,6 +1051,11 @@ KMOD_EXPORT int kmod_module_probe_insert_module(
10221051
return 0;
10231052
}
10241053

1054+
if (module_is_masked(mod)) {
1055+
ERR(mod->ctx, "module is masked: %s\n", kmod_module_get_name(mod));
1056+
return -EINVAL;
1057+
}
1058+
10251059
if (module_is_blacklisted(mod)) {
10261060
if (mod->alias != NULL && (flags & KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY))
10271061
return KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY;
@@ -1038,9 +1072,17 @@ KMOD_EXPORT int kmod_module_probe_insert_module(
10381072
if (err < 0)
10391073
return err;
10401074

1041-
if (flags & KMOD_PROBE_APPLY_BLACKLIST_ALL) {
1042-
struct kmod_list *filtered = NULL;
1075+
err = kmod_module_apply_filter(mod->ctx, KMOD_FILTER_MASK, list, &filtered);
1076+
kmod_module_unref_list(list);
1077+
if (err < 0)
1078+
return err;
10431079

1080+
if (filtered == NULL)
1081+
return -EINVAL;
1082+
1083+
list = filtered;
1084+
1085+
if (flags & KMOD_PROBE_APPLY_BLACKLIST_ALL) {
10441086
err = kmod_module_apply_filter(mod->ctx, KMOD_FILTER_BLACKLIST, list,
10451087
&filtered);
10461088
kmod_module_unref_list(list);

libkmod/libkmod.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,22 @@ struct kmod_list *kmod_list_prev(const struct kmod_list *list,
365365
*/
366366
struct kmod_config_iter;
367367

368+
/**
369+
* kmod_config_get_masks:
370+
* @ctx: kmod library context
371+
*
372+
* Retrieve an iterator to deal with the mask list maintained inside the
373+
* library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and
374+
* kmod_config_iter_next(). At least one call to kmod_config_iter_next() must
375+
* be made to initialize the iterator and check if it's valid.
376+
*
377+
* Returns: a new iterator over the masks or NULL on failure. Free it
378+
* with kmod_config_iter_free_iter().
379+
*
380+
* Since: 35
381+
*/
382+
struct kmod_config_iter *kmod_config_get_masks(const struct kmod_ctx *ctx);
383+
368384
/**
369385
* kmod_config_get_blacklists:
370386
* @ctx: kmod library context
@@ -905,12 +921,14 @@ int kmod_module_get_weakdeps(const struct kmod_module *mod, struct kmod_list **w
905921
* kmod_filter:
906922
* @KMOD_FILTER_BLACKLIST: filter modules in blacklist out
907923
* @KMOD_FILTER_BUILTIN: filter builtin modules out
924+
* @KMOD_FILTER_MASK: filter masked modules out
908925
*
909926
* Bitmask defining what gets filtered out, used by kmod_module_apply_filter().
910927
*/
911928
enum kmod_filter {
912929
KMOD_FILTER_BLACKLIST = 0x00001,
913930
KMOD_FILTER_BUILTIN = 0x00002,
931+
KMOD_FILTER_MASK = 0x00004,
914932
};
915933

916934
/**

libkmod/libkmod.sym

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,8 @@ global:
105105
kmod_config_get_weakdeps;
106106
kmod_module_get_weakdeps;
107107
} LIBKMOD_30;
108+
109+
LIBKMOD_35 {
110+
global:
111+
kmod_config_get_masks;
112+
} LIBKMOD_33;

man/modprobe.8.scd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ that for convenience, there is no difference between \_ and - in module names
2323
directory @MODULE_DIRECTORY@/$(uname -r) for all the modules and other files,
2424
except for the optional configuration files (see *modprobe.d*(5)). *modprobe* will
2525
also use module options specified on the kernel command line in the form of
26-
<module>.<option> and blacklists in the form of modprobe.blacklist=<module>.
26+
<module>.<option>, blacklists in the form of modprobe.blacklist=<module>
27+
and masks in modprobe.mask=<module>.
2728

2829
Note that unlike in 2.4 series Linux kernels (which are not supported by this
2930
tool) this version of *modprobe* does not do anything to the module itself: the

man/modprobe.d.5.scd

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ install _modulename_ _command_
108108
/sbin/modprobe barney; /sbin/modprobe --ignore-install fred
109109
$CMDLINE_OPTS"
110110

111+
mask _modulename_
112+
This command prevents _modulename_ from being loaded directly
113+
or through any of its aliases.
114+
111115
options _modulename_ _option_
112116
This command allows you to add options to the module _modulename_ (which
113117
might be an alias) every time it is inserted into the kernel: whether

scripts/setup-rootfs.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ map=(
111111
["test-modprobe/blacklist-loaded$MODULE_DIRECTORY/4.4.4/kernel/"]="mod-simple.ko"
112112
["test-modprobe/blacklist-softdep$MODULE_DIRECTORY/4.4.4/kernel/mod-foo-a.ko"]="mod-foo-a.ko"
113113
["test-modprobe/blacklist-softdep$MODULE_DIRECTORY/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
114+
["test-modprobe/mask$MODULE_DIRECTORY/4.4.4/kernel/mod-foo-a.ko"]="mod-foo-a.ko"
115+
["test-modprobe/mask$MODULE_DIRECTORY/4.4.4/kernel/mod-foo-b.ko"]="mod-foo-b.ko"
116+
["test-modprobe/mask$MODULE_DIRECTORY/4.4.4/kernel/mod-foo-c.ko"]="mod-foo-c.ko"
117+
["test-modprobe/mask$MODULE_DIRECTORY/4.4.4/kernel/mod-foo.ko"]="mod-foo.ko"
118+
["test-modprobe/mask-softdep$MODULE_DIRECTORY/4.4.4/kernel/mod-foo-a.ko"]="mod-foo-a.ko"
119+
["test-modprobe/mask-softdep$MODULE_DIRECTORY/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
114120
["test-depmod/modules-order-compressed$MODULE_DIRECTORY/4.4.4/kernel/drivers/block/cciss.ko"]="mod-fake-cciss.ko"
115121
["test-depmod/modules-order-compressed$MODULE_DIRECTORY/4.4.4/kernel/drivers/scsi/hpsa.ko"]="mod-fake-hpsa.ko"
116122
["test-depmod/modules-order-compressed$MODULE_DIRECTORY/4.4.4/kernel/drivers/scsi/scsi_mod.ko"]="mod-fake-scsi-mod.ko"

0 commit comments

Comments
 (0)