Skip to content

Commit a3780cc

Browse files
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. Co-authored-by: Jakub Ślepecki <[email protected]> Signed-off-by: Jakub Ślepecki <[email protected]> Signed-off-by: Dawid Osuchowski <[email protected]>
1 parent 3a492d8 commit a3780cc

35 files changed

+237
-9
lines changed

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
@@ -50,6 +50,11 @@ struct kmod_weakdep {
5050
unsigned int n_weak;
5151
};
5252

53+
const char *kmod_mask_get_modname(const struct kmod_list *l)
54+
{
55+
return l->data;
56+
}
57+
5358
const char *kmod_blacklist_get_modname(const struct kmod_list *l)
5459
{
5560
return l->data;
@@ -231,6 +236,27 @@ static int kmod_config_add_blacklist(struct kmod_config *config, const char *mod
231236
return 0;
232237
}
233238

239+
static int kmod_config_add_mask(struct kmod_config *config, const char *modname)
240+
{
241+
_cleanup_free_ char *p;
242+
struct kmod_list *list;
243+
244+
DBG(config->ctx, "modname=%s\n", modname);
245+
246+
_clang_suppress_alloc_ p = strdup(modname);
247+
if (!p)
248+
return -ENOMEM;
249+
250+
list = kmod_list_append(config->masks, p);
251+
if (!list)
252+
return -ENOMEM;
253+
254+
TAKE_PTR(p);
255+
config->masks = list;
256+
257+
return 0;
258+
}
259+
234260
static int kmod_config_add_softdep(struct kmod_config *config, const char *modname,
235261
const char *line)
236262
{
@@ -612,18 +638,24 @@ static char *weakdep_to_char(struct kmod_weakdep *dep)
612638
static void kcmdline_parse_result(struct kmod_config *config, char *modname, char *param,
613639
char *value)
614640
{
641+
bool is_blacklist, is_mask;
615642
if (modname == NULL || param == NULL)
616643
return;
617644

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

620-
if (streq(modname, "modprobe") && !strncmp(param, "blacklist=", 10)) {
647+
is_blacklist = !strncmp(param, "blacklist=", 10);
648+
is_mask = !strncmp(param, "mask=", 5);
649+
if (streq(modname, "modprobe") && (is_blacklist || is_mask)) {
621650
for (;;) {
622651
char *t = strsep(&value, ",");
623652
if (t == NULL)
624653
break;
625654

626-
kmod_config_add_blacklist(config, t);
655+
if (is_blacklist)
656+
kmod_config_add_blacklist(config, t);
657+
else
658+
kmod_config_add_mask(config, t);
627659
}
628660
} else {
629661
if (underscores(modname) < 0) {
@@ -829,6 +861,13 @@ static int kmod_config_parse(struct kmod_config *config, int fd, const char *fil
829861

830862
kmod_config_add_command(config, modname, installcmd, cmd,
831863
&config->install_commands);
864+
} else if (streq(cmd, "mask")) {
865+
char *modname = strtok_r(NULL, "\t ", &saveptr);
866+
867+
if (underscores(modname) < 0)
868+
goto syntax_error;
869+
870+
kmod_config_add_mask(config, modname);
832871
} else if (streq(cmd, "remove")) {
833872
char *modname = strtok_r(NULL, "\t ", &saveptr);
834873
char *removecmd = strtok_r(NULL, "\0", &saveptr);
@@ -878,6 +917,7 @@ void kmod_config_free(struct kmod_config *config)
878917
kmod_list_release(config->blacklists, free);
879918
kmod_list_release(config->options, free);
880919
kmod_list_release(config->install_commands, free);
920+
kmod_list_release(config->masks, free);
881921
kmod_list_release(config->remove_commands, free);
882922
kmod_list_release(config->softdeps, free);
883923
kmod_list_release(config->weakdeps, free);
@@ -1100,6 +1140,7 @@ int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **p_config,
11001140
enum config_type {
11011141
CONFIG_TYPE_BLACKLIST = 0,
11021142
CONFIG_TYPE_INSTALL,
1143+
CONFIG_TYPE_MASK,
11031144
CONFIG_TYPE_REMOVE,
11041145
CONFIG_TYPE_ALIAS,
11051146
CONFIG_TYPE_OPTION,
@@ -1150,6 +1191,10 @@ static struct kmod_config_iter *kmod_config_iter_new(const struct kmod_ctx *ctx,
11501191
iter->get_key = kmod_command_get_modname;
11511192
iter->get_value = kmod_command_get_command;
11521193
break;
1194+
case CONFIG_TYPE_MASK:
1195+
iter->list = config->masks;
1196+
iter->get_key = kmod_mask_get_modname;
1197+
break;
11531198
case CONFIG_TYPE_REMOVE:
11541199
iter->list = config->remove_commands;
11551200
iter->get_key = kmod_command_get_modname;
@@ -1200,6 +1245,14 @@ KMOD_EXPORT struct kmod_config_iter *kmod_config_get_install_commands(const stru
12001245
return kmod_config_iter_new(ctx, CONFIG_TYPE_INSTALL);
12011246
}
12021247

1248+
KMOD_EXPORT struct kmod_config_iter *kmod_config_get_masks(const struct kmod_ctx *ctx)
1249+
{
1250+
if (ctx == NULL)
1251+
return NULL;
1252+
1253+
return kmod_config_iter_new(ctx, CONFIG_TYPE_MASK);
1254+
}
1255+
12031256
// clang-format off
12041257
KMOD_EXPORT struct kmod_config_iter *kmod_config_get_remove_commands(const struct kmod_ctx *ctx)
12051258
// 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: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -735,12 +735,30 @@ static bool module_is_blacklisted(const struct kmod_module *mod)
735735
return false;
736736
}
737737

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

745763
if (ctx == NULL || output == NULL)
746764
return -ENOENT;
@@ -759,9 +777,21 @@ KMOD_EXPORT int kmod_module_apply_filter(const struct kmod_ctx *ctx,
759777
if ((filter_type & KMOD_FILTER_BUILTIN) && kmod_module_is_builtin(mod))
760778
continue;
761779

780+
if ((filter_type & KMOD_FILTER_MASK) && module_is_masked(mod)) {
781+
if (mod->required) {
782+
ERR(mod->ctx, "module is masked: %s\n",
783+
kmod_module_get_name(mod));
784+
err = -EINVAL;
785+
goto fail;
786+
} else
787+
continue;
788+
}
789+
762790
node = kmod_list_append(*output, mod);
763-
if (node == NULL)
791+
if (node == NULL) {
792+
err = -ENOMEM;
764793
goto fail;
794+
}
765795

766796
*output = node;
767797
kmod_module_ref(mod);
@@ -772,7 +802,7 @@ KMOD_EXPORT int kmod_module_apply_filter(const struct kmod_ctx *ctx,
772802
fail:
773803
kmod_module_unref_list(*output);
774804
*output = NULL;
775-
return -ENOMEM;
805+
return err;
776806
}
777807

778808
static int command_do(struct kmod_module *mod, const char *type, const char *cmd)
@@ -1006,7 +1036,7 @@ KMOD_EXPORT int kmod_module_probe_insert_module(
10061036
const void *data,
10071037
void (*print_action)(struct kmod_module *m, bool install, const char *options))
10081038
{
1009-
struct kmod_list *list = NULL, *l;
1039+
struct kmod_list *list = NULL, *l, *filtered = NULL;
10101040
struct probe_insert_cb cb;
10111041
int err;
10121042

@@ -1020,6 +1050,11 @@ KMOD_EXPORT int kmod_module_probe_insert_module(
10201050
return 0;
10211051
}
10221052

1053+
if (module_is_masked(mod)) {
1054+
ERR(mod->ctx, "module is masked: %s\n", kmod_module_get_name(mod));
1055+
return -EINVAL;
1056+
}
1057+
10231058
if (module_is_blacklisted(mod)) {
10241059
if (mod->alias != NULL && (flags & KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY))
10251060
return KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY;
@@ -1036,15 +1071,23 @@ KMOD_EXPORT int kmod_module_probe_insert_module(
10361071
if (err < 0)
10371072
return err;
10381073

1039-
if (flags & KMOD_PROBE_APPLY_BLACKLIST_ALL) {
1040-
struct kmod_list *filtered = NULL;
1074+
err = kmod_module_apply_filter(mod->ctx, KMOD_FILTER_MASK, list, &filtered);
1075+
kmod_module_unref_list(list);
1076+
if (err < 0)
1077+
return err;
1078+
1079+
if (filtered == NULL)
1080+
return -EINVAL;
10411081

1082+
list = filtered;
1083+
1084+
if (flags & KMOD_PROBE_APPLY_BLACKLIST_ALL) {
10421085
err = kmod_module_apply_filter(mod->ctx, KMOD_FILTER_BLACKLIST, list,
10431086
&filtered);
1087+
kmod_module_unref_list(list);
10441088
if (err < 0)
10451089
return err;
10461090

1047-
kmod_module_unref_list(list);
10481091
if (filtered == NULL)
10491092
return KMOD_PROBE_APPLY_BLACKLIST_ALL;
10501093

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 @DISTCONFDIR@/`uname -r` for all the modules and other files, except
2424
for the optional configuration files (see *modprobe.d*(5)). *modprobe* will also
2525
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
@@ -105,6 +105,12 @@ map=(
105105
["test-modprobe/blacklist-loaded$MODULE_DIRECTORY/4.4.4/kernel/"]="mod-simple.ko"
106106
["test-modprobe/blacklist-softdep$MODULE_DIRECTORY/4.4.4/kernel/mod-foo-a.ko"]="mod-foo-a.ko"
107107
["test-modprobe/blacklist-softdep$MODULE_DIRECTORY/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
108+
["test-modprobe/mask$MODULE_DIRECTORY/4.4.4/kernel/mod-foo-a.ko"]="mod-foo-a.ko"
109+
["test-modprobe/mask$MODULE_DIRECTORY/4.4.4/kernel/mod-foo-b.ko"]="mod-foo-b.ko"
110+
["test-modprobe/mask$MODULE_DIRECTORY/4.4.4/kernel/mod-foo-c.ko"]="mod-foo-c.ko"
111+
["test-modprobe/mask$MODULE_DIRECTORY/4.4.4/kernel/mod-foo.ko"]="mod-foo.ko"
112+
["test-modprobe/mask-softdep$MODULE_DIRECTORY/4.4.4/kernel/mod-foo-a.ko"]="mod-foo-a.ko"
113+
["test-modprobe/mask-softdep$MODULE_DIRECTORY/4.4.4/kernel/mod-simple.ko"]="mod-simple.ko"
108114
["test-depmod/modules-order-compressed$MODULE_DIRECTORY/4.4.4/kernel/drivers/block/cciss.ko"]="mod-fake-cciss.ko"
109115
["test-depmod/modules-order-compressed$MODULE_DIRECTORY/4.4.4/kernel/drivers/scsi/hpsa.ko"]="mod-fake-hpsa.ko"
110116
["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)