-
Notifications
You must be signed in to change notification settings - Fork 52
Add mask command and modprobe test with blacklist #312
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
PR Title: PR Description: |
To add more context to our initial description. In PR there are three options to prevent module from loading:
Install still provides the best flexibility: user may specify either Blacklist puts the most burden on the user. If they choose to disable module with it (in contrast to just limiting the alias resolution), they need to make sure their scripts use either aliases or -b. Mask intends to provide a strict (in contrast to install) and clear intent-based (in contrast to both blacklist and install) option that |
5b5226c
to
abb3e2a
Compare
The latest force-push was to address the formatting issue reported by CI: https://github.com/kmod-project/kmod/actions/runs/13732774455/job/38592878799?pr=312 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall I'm loving how you went above and beyond on the prep (blacklist tests) patch. There's one serious note, but the rest are cosmetic suggestions.
Thanks team o/
libkmod/libkmod-config.c
Outdated
if (streq(modname, "modprobe") && !strncmp(param, "blacklist=", 10)) { | ||
if (streq(modname, "modprobe")) { | ||
bool is_mask = !strncmp(param, "mask=", 5); | ||
bool is_blacklist = !strncmp(param, "blacklist=", 10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self: replace strncmp
with strstartswith
tree-wide.
libkmod/libkmod-config.c
Outdated
@@ -615,13 +641,18 @@ static void kcmdline_parse_result(struct kmod_config *config, char *modname, cha | |||
|
|||
DBG(config->ctx, "%s %s\n", modname, param); | |||
|
|||
if (streq(modname, "modprobe") && !strncmp(param, "blacklist=", 10)) { | |||
if (streq(modname, "modprobe")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We seems to be changing the logic here, instead of extending it. We should be using something like below, right?
if (streq(modname, "modprobe") && (!strncmp(param, "blacklist=", 10) || !strncmp(param, "mask=", 5)) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, will change
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
libkmod/libkmod-config.c
Outdated
if (underscores(modname) < 0) | ||
goto syntax_error; | ||
|
||
kmod_config_add_mask(config, modname); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: let's move the mask
hunks just above the remove
, across the patch.
Optional bonus points - alpha sort the rest (across the tree) with a follow-up commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do across the patch
Jakub is willing to add to that and sort across the tree
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is done. I don't think we adjusted it across the tree, @whythefyouflying?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is done. I don't think we adjusted it across the tree, @whythefyouflying?
It was not. I believe that would best be suited in a separate series/PR.
}, | ||
.modules_loaded = "", | ||
.modules_not_loaded = "mod-simple", | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we test that mask=dependency
with modprobe dependee
fails?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm I guess the behaviour will vary based on the dependency type AFAICT:
- (hard) dependency - failure
- softdep - success
- weakdep - not sure, need to check
Currently we always return success, which I'm not sure is the best. Need to do some testing over the weekend...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, I'd say:
- dependency - module does not load, modprobe status is non-zero
- softdep - target module loads without softdep(s), status is zero
- weakdep - target module loads without weakdep(s), status is zero
I added such tests in local branch and they will be included in v3. I settled on weakdep behaviour because of its description in manual pages "Those are similar to pre softdep" and "userspace doesn't attempt to load that dependency before the specified module."
This is not what's happening right now, so we'll fix it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed in a3780cc: hard and soft dependencies now behave like above. Weakdep has no effect at all on modprobe so it's ignored, but since it would fall into not required category it would behave like softdep.
@@ -163,6 +163,7 @@ static int show_config(struct kmod_ctx *ctx) | |||
const char *name; | |||
struct kmod_config_iter *(*get_iter)(const struct kmod_ctx *ctx); | |||
} ci[] = { | |||
{ "mask", kmod_config_get_masks }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@evelikov What would be your guidance on the placement of this line? I agree with alpha sorting in the rest of the patch, but in here I feel like mask list should be printed first, given it is more restrictive than blacklist and will most likely not be a huge list as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow how that makes a difference. People/tools already need to parse the whole output, regardless of how long/short respective sections are.
Mind you, the suggestion is a bit bike-sheddy so don't take it too seriously.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one is not done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow how that makes a difference. People/tools already need to parse the whole output, regardless of how long/short respective sections are.
Mind you, the suggestion is a bit bike-sheddy so don't take it too seriously.
Alpha sorted everything across the patch except this line.
I believe from the human user perspective, given mask is the most restrictive option, it would be good UI to have it displayed first. If we want to alpha sort everything in show_config()
then we should also print alias
first and that is not the case.
I was initially confused at
@jspcki Putting |
libkmod/libkmod-module.c
Outdated
@@ -1020,6 +1037,9 @@ KMOD_EXPORT int kmod_module_probe_insert_module( | |||
return 0; | |||
} | |||
|
|||
if (module_is_masked(mod)) | |||
return 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Loading a masked module should not return success.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Compare systemd:
root@daniel-desktop3:~# systemctl start badservice
Failed to start badservice.service: Unit badservice.service is masked.
root@daniel-desktop3:~# echo $?
1
root@daniel-desktop3:~#
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was mentioned just above, with some potential caveats wrt the different dependency types.
If you can share your expectations for each use-case, that would be appreciated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
abb3e2a
to
a3780cc
Compare
Incorrect. |
libkmod/libkmod-module.c
Outdated
if (mod->required) { | ||
ERR(mod->ctx, "module is masked: %s\n", | ||
kmod_module_get_name(mod)); | ||
err = -EINVAL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to hear opinions/suggestions on EINVAL in this case and in 1080. I thought about using custom error, but I disliked the part that it "only so happened to" not collide with errno. Otherwise we could return positive error (even though it's not a direct result of flags per kmod_module_probe_insert_module
description) and handle it in modprobe.c.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer standard errno codes - don't have a strong opinion either way though.
libkmod/libkmod-module.c
Outdated
@@ -759,9 +777,21 @@ KMOD_EXPORT int kmod_module_apply_filter(const struct kmod_ctx *ctx, | |||
if ((filter_type & KMOD_FILTER_BUILTIN) && kmod_module_is_builtin(mod)) | |||
continue; | |||
|
|||
if ((filter_type & KMOD_FILTER_MASK) && module_is_masked(mod)) { | |||
if (mod->required) { | |||
ERR(mod->ctx, "module is masked: %s\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could s/module/dependency/ if it feels more right. It will never be the module itself because of earlier check in 1074 unless used in different conditions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Module is fine IMHO. It's A module, maybe not THE module the user (API or otherwise) is directly loading, but that's fine.
Thanks for the updates team. Been quite busy with IRL, but I'll try to find some time this week to review the new version. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a few minor comments - with or without them the PR looks good. Thumbs up from me.
Would be interesting to hear Lucas' POV wrt the EINVAL et al.
libkmod/libkmod-module.c
Outdated
@@ -759,9 +777,21 @@ KMOD_EXPORT int kmod_module_apply_filter(const struct kmod_ctx *ctx, | |||
if ((filter_type & KMOD_FILTER_BUILTIN) && kmod_module_is_builtin(mod)) | |||
continue; | |||
|
|||
if ((filter_type & KMOD_FILTER_MASK) && module_is_masked(mod)) { | |||
if (mod->required) { | |||
ERR(mod->ctx, "module is masked: %s\n", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Module is fine IMHO. It's A module, maybe not THE module the user (API or otherwise) is directly loading, but that's fine.
libkmod/libkmod-module.c
Outdated
if (mod->required) { | ||
ERR(mod->ctx, "module is masked: %s\n", | ||
kmod_module_get_name(mod)); | ||
err = -EINVAL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer standard errno codes - don't have a strong opinion either way though.
err = -EINVAL; | ||
goto fail; | ||
} else | ||
continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Style nit:
if !required
continue
ERR(...)
err = ...;
goto fail;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
if (err < 0) | ||
return err; | ||
|
||
kmod_module_unref_list(list); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nicely spotted. Let's split this one-line corner-case memory leak fix in its* own commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out of curiosity (aka non-blocking question): What is the command which produces the Sanitizer leak report? Does one need to modify code or it happens out of the box?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had ASAN complaining primarily at 1072 when we had a similar sequence of statements: filter -> return -> unref. You'd need to hit any of the failing conditions of the filter: (ctx == NULL || output == NULL)
, mod->required
, or kmod_list_append(*output, mod) == NULL
. Other than required
they are unlikely. Right now easiest way would be to inject error there manually and it's the way I generated sanitizer output for the commit.
Until now blacklist command was only covered by test-blacklist at libkmod interface level. A regular user will usually interact with it via modprobe(8). This commit adds tests for modprobe, alias filtering, and -b option. It is also intended as an example of -b usage. Co-authored-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com> Signed-off-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com> Signed-off-by: Jakub Ślepecki <jakub.slepecki@intel.com>
In case of error path this might have led to, for example: ==86629==ERROR: LeakSanitizer: detected memory leaks Direct leak of 24 byte(s) in 1 object(s) allocated from: #0 0x7fa904b20e15 (/usr/lib/gcc/x86_64-pc-linux-gnu/15.1.1/../../../../lib/libasan.so+0x120e15) (BuildId: 9dccfc42ea2d9790ff7cf76cc8a3210650e604e0) #1 0x55d74820fc8a ($kmod/build/kmod+0xefc8a) (BuildId: e7c136c95271cf020398e33fd5577d82adc7a47c) kmod-project#2 0x55d7482173a6 ($kmod/build/kmod+0xf73a6) (BuildId: e7c136c95271cf020398e33fd5577d82adc7a47c) kmod-project#3 0x55d74821a617 ($kmod/build/kmod+0xfa617) (BuildId: e7c136c95271cf020398e33fd5577d82adc7a47c) kmod-project#4 0x55d7481e2d80 ($kmod/build/kmod+0xc2d80) (BuildId: e7c136c95271cf020398e33fd5577d82adc7a47c) kmod-project#5 0x55d7481e314f ($kmod/build/kmod+0xc314f) (BuildId: e7c136c95271cf020398e33fd5577d82adc7a47c) kmod-project#6 0x55d7481e658c ($kmod/build/kmod+0xc658c) (BuildId: e7c136c95271cf020398e33fd5577d82adc7a47c) kmod-project#7 0x7fa9038376b4 (/usr/lib/libc.so.6+0x276b4) (BuildId: 468e3585c794491a48ea75fceb9e4d6b1464fc35) kmod-project#8 0x7fa903837768 (/usr/lib/libc.so.6+0x27768) (BuildId: 468e3585c794491a48ea75fceb9e4d6b1464fc35) kmod-project#9 0x55d7481c3334 ($kmod/build/kmod+0xa3334) (BuildId: e7c136c95271cf020398e33fd5577d82adc7a47c) Indirect leak of 4120 byte(s) in 1 object(s) allocated from: #0 0x7fa904b2073d (/usr/lib/gcc/x86_64-pc-linux-gnu/15.1.1/../../../../lib/libasan.so+0x12073d) (BuildId: 9dccfc42ea2d9790ff7cf76cc8a3210650e604e0) #1 0x55d7481eb8eb ($kmod/build/kmod+0xcb8eb) (BuildId: e7c136c95271cf020398e33fd5577d82adc7a47c) kmod-project#2 0x55d7481f6fee ($kmod/build/kmod+0xd6fee) (BuildId: e7c136c95271cf020398e33fd5577d82adc7a47c) kmod-project#3 0x55d7481e52c4 ($kmod/build/kmod+0xc52c4) (BuildId: e7c136c95271cf020398e33fd5577d82adc7a47c) kmod-project#4 0x7fa9038376b4 (/usr/lib/libc.so.6+0x276b4) (BuildId: 468e3585c794491a48ea75fceb9e4d6b1464fc35) kmod-project#5 0x7fa903837768 (/usr/lib/libc.so.6+0x27768) (BuildId: 468e3585c794491a48ea75fceb9e4d6b1464fc35) kmod-project#6 0x55d7481c3334 ($kmod/build/kmod+0xa3334) (BuildId: e7c136c95271cf020398e33fd5577d82adc7a47c) [...] SUMMARY: AddressSanitizer: 5701 byte(s) leaked in 27 allocation(s). Co-authored-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com> Signed-off-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com> Signed-off-by: Jakub Ślepecki <jakub.slepecki@intel.com>
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 <jakub.slepecki@intel.com> Signed-off-by: Jakub Ślepecki <jakub.slepecki@intel.com> Signed-off-by: Dawid Osuchowski <dawid.osuchowski@linux.intel.com>
a3780cc
to
d8d5d51
Compare
We have rebased the code to latest master and addressed review concerns |
@lucasdemarchi Can you please take a look? |
Closes: #40
libkmod: add mask command
Co-authored-by: Jakub Ślepecki jakub.slepecki@intel.com
Signed-off-by: Dawid Osuchowski dawid.osuchowski@intel.com
Signed-off-by: Jakub Ślepecki jakub.slepecki@intel.com
testsuite: test-modprobe: modprobe with blacklist
Co-authored-by: Dawid Osuchowski dawid.osuchowski@intel.com
Signed-off-by: Jakub Ślepecki jakub.slepecki@intel.com
Signed-off-by: Dawid Osuchowski dawid.osuchowski@intel.com