Skip to content
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

usersession/userd: query xdg-mime to check for fallback handlers of a given scheme #11200

Merged

Conversation

bboozzoo
Copy link
Collaborator

@bboozzoo bboozzoo commented Jan 4, 2022

Most of the handling is of xdg-open requests from the snaps is done by
xdg-desktop-portal now, the handler in userd remains a fallback for scenarios
where the desktop setup is incomplete. The code of io.snapcraft.OpenURL()
handler would only allow a handful of schemes to be passed to xdg-open on the
host side. However, updating the list of schemes manually has proven be to
unmaintainable, and got filled with various vendor specific entries.

In #7731 (comment) an
approach was proposed to use xdg-query to find out whether there is handler for
given scheme on the host side, and if so allow the URL to be passed to xdg-open,
which is implemented in this patch.

… given scheme

Most of the handling is of xdg-open requests from the snaps id done by
xdg-desktop-protal now, the handler in userd remains a fallback for scenarios
where the desktop setup is incomplete. The code of io.snapcraft.OpenURL()
handler would only allow a handful of schemes to be passed to xdg-open on the
host side. However, updating the list of schemes manually has proven be to
unmaintainable, and got filled with various vendor specific entries.

In snapcore#7731 (comment) an
approach was proposed to use xdg-query to find out whether there is handler for
given scheme on the host side, and if so allow the URL to be passed to xdg-open,
which is implemented in this patch.

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
@bboozzoo bboozzoo added the Needs security review Can only be merged once security gave a :+1: label Jan 4, 2022
Copy link
Member

@anonymouse64 anonymouse64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a couple little nitpicks but overall looks great to me, I do think we need a security review on this however

// OpenURL implements the 'OpenURL' method of the 'io.snapcraft.Launcher'
// DBus interface. Before the provided url is passed to xdg-open the scheme is
// validated against a list of allowed schemes. All other schemes are denied.
func (s *Launcher) OpenURL(addr string, sender dbus.Sender) *dbus.Error {
logger.Noticef("open url: %q", addr)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be a Noticef? Or a Debugf?

if err != nil {
logger.Noticef("cannot obtain scheme handler for %q: %v", u.Scheme, err)
}
isAllowed = isAllowed || has
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we know isAllowed is false in this branch, we could just do

Suggested change
isAllowed = isAllowed || has
isAllowed = has

Comment on lines 118 to 119
c.Assert(err, NotNil)
c.Assert(err, ErrorMatches, `Supplied URL scheme "fallback-scheme" is not allowed`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
c.Assert(err, NotNil)
c.Assert(err, ErrorMatches, `Supplied URL scheme "fallback-scheme" is not allowed`)
c.Assert(err, ErrorMatches, `Supplied URL scheme "fallback-scheme" is not allowed`)

@@ -153,10 +157,26 @@ func checkOnClassic() *dbus.Error {
return nil
}

// see https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#file-naming
var validDesktopFileName = regexp.MustCompile(`^[A-Za-z-_][A-Za-z0-9-_]*(\.[A-Za-z-_][A-Za-z0-9-_]*)*\.desktop$`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spot checked a few cases and this looks correct to me

@@ -26,6 +26,27 @@ prepare: |
/ \
org.freedesktop.DBus.Peer.Ping

# setup the handler
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the spread test

Copy link
Contributor

@MiguelPires MiguelPires left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
@codecov-commenter
Copy link

codecov-commenter commented Jan 10, 2022

Codecov Report

Merging #11200 (597fef7) into master (3782a94) will increase coverage by 0.00%.
The diff coverage is 76.92%.

Impacted file tree graph

@@           Coverage Diff           @@
##           master   #11200   +/-   ##
=======================================
  Coverage   78.26%   78.26%           
=======================================
  Files         930      930           
  Lines      106315   106340   +25     
=======================================
+ Hits        83210    83231   +21     
- Misses      17936    17939    +3     
- Partials     5169     5170    +1     
Flag Coverage Δ
unittests 78.26% <76.92%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
usersession/userd/launcher.go 69.49% <76.92%> (+1.74%) ⬆️
cmd/snap/cmd_aliases.go 90.14% <0.00%> (-1.41%) ⬇️
osutil/synctree.go 79.24% <0.00%> (+2.83%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3782a94...597fef7. Read the comment docs.

Copy link
Contributor

@mardy mardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with a nitpick :-)


func schemeHasHandler(scheme string) (bool, error) {
cmd := exec.Command("xdg-mime", "query", "default", "x-scheme-handler/"+scheme)
out, err := cmd.CombinedOutput()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick: it would be more robust to use just Output() here, in case the xdg-mime program emits some warning on the stderr (or even just some debugging message). For example if the combined output was this:

Warning: myapp.desktop: invalid desktop file [<- stderr]
gimp.desktop [<- stdout]

the current implementation of this function would return false, whereas ideally it should return true.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a TODO here to consider using Output. TBH despite my attempts I was not able to make xdg-mime log anything to stderr even whe ~/.config/mimeapps.list was clearly malformed or missing.

Copy link
Collaborator

@alexmurray alexmurray left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

URL parsing in Go looks pretty safe - so it doesn't appear a URL could try and inject shell content or similar via the URI scheme - plus exec.Command() doesn't execute a shell either so even if a user could somehow inject extra content, it won't get executed when we go and run xdg-mime. Finally, if a user has installed an application then I don't see a reason not to honor that which this implementation allows.

So from a security (and usability) point of view, this looks great.

Thanks.

@alexmurray alexmurray removed the Needs security review Can only be merged once security gave a :+1: label Feb 1, 2022
…me support

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
@jhenstridge
Copy link
Contributor

Looking at xdg-desktop-portal, it will skip prompting the user before launching the URI if:

  1. the URI uses a "safe" scheme, which is one of http, https, ftp, mailto, webal or calendar, and there is a default app for that scheme.
  2. there is only one handler for the scheme.
  3. the user has been prompted for permission and chosen the same option more than a set number of times (defaulting to 3).

The proposed behaviour here is not identical (i.e. it's going to differ if there are multiple providers available for a scheme), but seems reasonable. While snaps can modify mime default handlers via userd, it does result in a zenity dialog prompt. If there was a security problem, I'd tend to think that end would be the problem.

@bboozzoo
Copy link
Collaborator Author

bboozzoo commented Feb 2, 2022

@mvo5 this is ready to land, can you merge the branch please?

@mvo5 mvo5 merged commit 3885231 into snapcore:master Feb 2, 2022
bboozzoo added a commit to bboozzoo/snapd that referenced this pull request Mar 8, 2022
PR snapcore#11200 added a way to query for a
handler for any given URL scheme. Extend this and ask the user whether a URL
should be opened by a given handler. This is similar to what the desktop portal
does, but instead of presenting the app chooser dialog, we only present the user
with a yes/no question and the default handler.

Note, that the implementation is only for the fallback io.snapcraft.Launcher
handler, which would be called only if the desktop portal is not available.

Signed-off-by: Maciej Borzecki <maciej.zenon.borzecki@canonical.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
8 participants