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
interfaces: fix udev tagging for hooks (2.29) #4146
Conversation
This will just allow us to add apps/hooks easily later. Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
This patch introduces functionality similar to what other specification types allow: the snippet is automatically added to all the apps and hooks that affect the given plug or slot. Udev is a bit special in that it allows arbitrary udev programs to be injected (for instance, the network manager interface requires this) but most interfaces don't need that generic functionality and instead just want to tag a device so that all the apps associated with the plug or slot have acess to it. When we added hooks the udev backend was never updated to handle them so we now noticed that hooks don't have any udev tagging at all. With this new method we can use a much simpler API to do the right thing while still retain the ability to add arbitrary free-form snippets everywhere. Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
This automatically handles both apps and hooks, leading to simpler and more correct code. The only cases that still use AddSnippet are injecting non-tagging expressions (udisks, modem-manager, etc). Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
The "new" udev is where the TAG += ... part is handled automatically by the common interface and now contains support for both apps and hooks. Signed-off-by: Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
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 looks good and simplifies things which is great. OTOH quite a bit of churn so I have some questions inline.
@@ -56,6 +70,8 @@ func (spec *Specification) AddConnectedPlug(iface interfaces.Interface, plug *in | |||
UDevConnectedPlug(spec *Specification, plug *interfaces.Plug, plugAttrs map[string]interface{}, slot *interfaces.Slot, slotAttrs map[string]interface{}) error | |||
} | |||
if iface, ok := iface.(definer); ok { | |||
spec.securityTags = plug.SecurityTags() | |||
defer func() { spec.securityTags = nil }() |
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.
Why are we doing this? This feels strange (and dangerous), I mean, if its something that should only be valid during the iface.UDevConnectedPlug() call maybe it should be an input parameter there instead? Actually we already pass "plug" in there, so why is UdevConntecedPlug not just using plug.SecurityTags() ?
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 do this in all the other backends. This is just making the API changes smaller and consistent with other backends.
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 agree, it merits a rethink at some point, but yes, I saw the other backends work like this as well
@@ -139,8 +139,8 @@ func (s *MirInterfaceSuite) TestSecCompOnClassic(c *C) { | |||
func (s *MirInterfaceSuite) TestUDevSpec(c *C) { | |||
udevSpec := &udev.Specification{} | |||
c.Assert(udevSpec.AddPermanentSlot(s.iface, s.coreSlot), IsNil) | |||
c.Assert(udevSpec.Snippets(), HasLen, 1) | |||
c.Assert(udevSpec.Snippets()[0], testutil.Contains, `KERNEL=="event[0-9]*", TAG+="snap_mir-server_mir"`) | |||
c.Assert(udevSpec.Snippets(), HasLen, 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.
Why did this change from 1 snippet to 5 snippets?
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.
Each snippet that tags a device is now a separate entry. Before they were one big blob.
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.
The test is a bit relaxed now with checking length only. I think it would be nice to have a 'Contains' check, like we do for others.
@@ -207,9 +207,9 @@ func (s *ModemManagerInterfaceSuite) TestUsedSecuritySystems(c *C) { | |||
|
|||
udevSpec := &udev.Specification{} | |||
c.Assert(udevSpec.AddPermanentSlot(s.iface, s.slot), IsNil) | |||
c.Assert(udevSpec.Snippets(), HasLen, 1) | |||
c.Assert(udevSpec.Snippets(), HasLen, 2) |
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.
Why did this change to two? One extra for a hook?
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.
Same as above. In the past this was one multi-line snippet.
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.
lgtm, some questions about SUBSYSTEM vs SUBSYSTEMS
spec.TagDevice(fmt.Sprintf(`SUBSYSTEM=="hidraw", KERNEL=="%s"`, strings.TrimPrefix(path, "/dev/"))) | ||
} else { | ||
spec.TagDevice(fmt.Sprintf(`IMPORT{builtin}="usb_id" | ||
SUBSYSTEM=="hidraw", SUBSYSTEMS=="usb", ATTRS{idVendor}=="%04x", ATTRS{idProduct}=="%04x"`, usbVendor, usbProduct)) |
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.
is SUBSYSTEMS="usb" correct here? I remember jdstrand changed recently SUBSYSTEMS to SUBSYSTEM in some cases
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.
for other reasons I was reading the udev docs, it seems this means the hidraw subsystem under the usb devices, so it seems plausible
spec.TagDevice(fmt.Sprintf(`SUBSYSTEM=="tty", KERNEL=="%s"`, strings.TrimPrefix(path, "/dev/"))) | ||
} else { | ||
spec.TagDevice(fmt.Sprintf(`IMPORT{builtin}="usb_id" | ||
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="%04x", ATTRS{idProduct}=="%04x"`, usbVendor, usbProduct)) |
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.
is SUBSYSTEMS="usb" correct here? I remember jdstrand changed recently SUBSYSTEMS to SUBSYSTEM in some cases
@@ -56,6 +70,8 @@ func (spec *Specification) AddConnectedPlug(iface interfaces.Interface, plug *in | |||
UDevConnectedPlug(spec *Specification, plug *interfaces.Plug, plugAttrs map[string]interface{}, slot *interfaces.Slot, slotAttrs map[string]interface{}) error | |||
} | |||
if iface, ok := iface.(definer); ok { | |||
spec.securityTags = plug.SecurityTags() | |||
defer func() { spec.securityTags = nil }() |
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 agree, it merits a rethink at some point, but yes, I saw the other backends work like this as well
The test relies on the "old" snapd-xdg-open deb package. However with the promotion of snapd 2.28.5 into xenial-updates the pervious snapd-xdg-open version 0.0.0~16.04 is no longer available to download. This means we can not run the test. Disable for now until we find a way to 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.
LGTM, with two remarks.
@@ -139,8 +139,8 @@ func (s *MirInterfaceSuite) TestSecCompOnClassic(c *C) { | |||
func (s *MirInterfaceSuite) TestUDevSpec(c *C) { | |||
udevSpec := &udev.Specification{} | |||
c.Assert(udevSpec.AddPermanentSlot(s.iface, s.coreSlot), IsNil) | |||
c.Assert(udevSpec.Snippets(), HasLen, 1) | |||
c.Assert(udevSpec.Snippets()[0], testutil.Contains, `KERNEL=="event[0-9]*", TAG+="snap_mir-server_mir"`) | |||
c.Assert(udevSpec.Snippets(), HasLen, 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.
The test is a bit relaxed now with checking length only. I think it would be nice to have a 'Contains' check, like we do for others.
spec.AddSnippet(fmt.Sprintf("SUBSYSTEM==\"hidraw\", KERNEL==\"%s\", TAG+=\"%s\"", strings.TrimPrefix(path, "/dev/"), tag)) | ||
|
||
} else { | ||
spec.AddSnippet(udevUsbDeviceSnippet("hidraw", usbVendor, usbProduct, "TAG", tag)) |
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.
Why keeping udevUsbDeviceSnippet in utils, can we remove it as in #4144? Did you forget about cherry-picking something from the other branch?
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 wanted to stay minimal in this approach. I can pull more from 4144 if necessary.
Codecov Report
@@ Coverage Diff @@
## release/2.29 #4146 +/- ##
================================================
- Coverage 75.6% 75.58% -0.03%
================================================
Files 433 433
Lines 37277 37253 -24
================================================
- Hits 28182 28156 -26
- Misses 7124 7126 +2
Partials 1971 1971
Continue to review full report at Codecov.
|
This is a backport of #4144 for 2.29; Original description follows.
This branch aims to fix udev tagging to support hooks in addition to apps that were added earlier.
There are three main patches here:
The only remaining uses of spec.AddSnippet are special-cases that add large chunk of arbitrary
udev code that is not specifically aiming to tag a device.
This passes local unit testing, no testing was done on any hardware.
Signed-off-by: Zygmunt Krynicki zygmunt.krynicki@canonical.com