Skip to content

Commit

Permalink
i/b/kernel-module-load: support "dynamic" load attribute
Browse files Browse the repository at this point in the history
As far as the code in the interfaces/buildint module is concerned, this
is nearly equivalent to the "none" load type. It's the code in snapctl
that will be checking for this attribute and enable runtime loading and
unloading of the allowed kernel modules if the attribute is set.
  • Loading branch information
mardy committed May 31, 2022
1 parent 35bd16f commit 820896f
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 6 deletions.
11 changes: 8 additions & 3 deletions interfaces/builtin/kernel_module_load.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const (
loadNone loadOption = iota
loadDenied
loadOnBoot
loadDynamic
)

type ModuleInfo struct {
Expand Down Expand Up @@ -95,6 +96,8 @@ func enumerateModules(plug interfaces.Attrer, handleModule func(moduleInfo *Modu
load = loadDenied
case "on-boot":
load = loadOnBoot
case "dynamic":
load = loadDynamic
default:
return fmt.Errorf(`kernel-module-load "load" value is unrecognized: %q`, loadString)
}
Expand Down Expand Up @@ -139,7 +142,9 @@ func validateOptionsAttr(moduleInfo *ModuleInfo) error {
return errors.New(`kernel-module-load "options" attribute incompatible with "load: denied"`)
}

if !kernelModuleOptionsRegexp.MatchString(moduleInfo.options) {
// Use a variable to make the next `if` more readable
dynamicLoadingWithAnyOptions := moduleInfo.load == loadDynamic && moduleInfo.options == "*"
if !dynamicLoadingWithAnyOptions && !kernelModuleOptionsRegexp.MatchString(moduleInfo.options) {
return fmt.Errorf(`kernel-module-load "options" attribute contains invalid characters: %q`, moduleInfo.options)
}

Expand Down Expand Up @@ -194,8 +199,8 @@ func (iface *kernelModuleLoadInterface) KModConnectedPlug(spec *kmod.Specificati
break
}
fallthrough
case loadNone:
if len(moduleInfo.options) > 0 {
case loadNone, loadDynamic:
if len(moduleInfo.options) > 0 && moduleInfo.options != "*" {
// module options might include filesystem paths. Beside
// supporting hardcoded paths, it makes sense to support also
// paths to files provided by the snap; for this reason, we
Expand Down
19 changes: 16 additions & 3 deletions interfaces/builtin/kernel_module_load_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ plugs:
options: param_1=ok param_2=false
- name: expandvar
options: opt=$FOO path=$SNAP_COMMON/bar
- name: dyn-module1
load: dynamic
options: opt1=v1 opt2=v2
- name: dyn-module2
load: dynamic
options: "*"
apps:
app:
plugs: [kmod]
Expand Down Expand Up @@ -155,6 +161,11 @@ apps:
"modules:\n - name: pcspkr\n options: \"no-dashes\"",
`kernel-module-load "options" attribute contains invalid characters: "no-dashes"`,
},
{
// "*" is only allowed for `load: dynamic`
"modules:\n - name: pcspkr\n options: \"*\"",
`kernel-module-load "options" attribute contains invalid characters: "\*"`,
},
{
"modules:\n - name: pcspkr\n load: denied\n options: p1=true",
`kernel-module-load "options" attribute incompatible with "load: denied"`,
Expand All @@ -176,9 +187,11 @@ func (s *KernelModuleLoadInterfaceSuite) TestKModSpec(c *C) {
"mymodule1": true,
})
c.Check(spec.ModuleOptions(), DeepEquals, map[string]string{
"mymodule1": "p1=3 p2=true p3",
"mymodule2": "param_1=ok param_2=false",
"expandvar": "opt=$FOO path=/var/snap/consumer/common/bar",
"mymodule1": "p1=3 p2=true p3",
"mymodule2": "param_1=ok param_2=false",
"expandvar": "opt=$FOO path=/var/snap/consumer/common/bar",
"dyn-module1": "opt1=v1 opt2=v2",
// No entry for dyn-module2, which has options set to "*"
})
c.Check(spec.DisallowedModules(), DeepEquals, []string{"forbidden"})
}
Expand Down

0 comments on commit 820896f

Please sign in to comment.