RESOLVED FIXED Bug 211131
[WPE][GTK] Paths should be canonicalized before calling bwrap
https://bugs.webkit.org/show_bug.cgi?id=211131
Summary [WPE][GTK] Paths should be canonicalized before calling bwrap
Jack Hill
Reported 2020-04-28 09:17:31 PDT
Before setting up worker sandboxes with Bubblewrap, the paths should be canonicalized by calling realpath(). Bubblewrap does not handle paths with absolute symlinks <https://github.com/containers/bubblewrap/issues/195>, so this avoids that problem. The error message presented by bwrap in such a case is, "bwrap: Can't create file at /path/to/symbolic/link: No such file or directory". This problem was observed on GNU Guix with WebKitGTK 2.28.1 <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=40837>.
Attachments
Patch (3.48 KB, patch)
2022-02-23 08:20 PST, apteryx
no flags
Patch (3.47 KB, patch)
2022-02-23 11:20 PST, apteryx
no flags
Patch (3.44 KB, patch)
2022-02-23 14:12 PST, apteryx
no flags
apteryx
Comment 1 2022-02-23 08:20:08 PST
Adrian Perez
Comment 2 2022-02-23 08:29:27 PST
(In reply to apteryx from comment #1) > Created attachment 452983 [details] > Patch The patch looks reasonable to me, but I am a bit shy to approve it because there are other reviewers with more knowledge about of the sandbox code. If Michael or Patrick could rubber-stamp this, that would be perfect.
Michael Catanzaro
Comment 3 2022-02-23 08:58:43 PST
Comment on attachment 452983 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=452983&action=review > Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp:334 > +static void bindSymlinksRealPath(Vector<CString>& args, const char* path, const char* bindOption = "--ro-bind") > +{ > + WTF::String realPath = FileSystem::realPath(path); > + if (path == realPath) { > + const char* rpath = realPath.utf8().data(); > + args.appendVector(Vector<CString>({ bindOption, rpath, rpath })); > + } > +} I'm a little confused here. What I expected: if the path is a symlink, bind its target instead so the operation doesn't fail. What you have here: if the path is a symlink (path != realPath), ignore it. Sure, the operation will not fail if you skip it, but won't you still wind up with a broken sandbox? > Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp:352 > + bindSymlinksRealPath(args, path, bindType); > + // As /etc is exposed wholesale, do not layer extraneous bind Style nit: leave a blank line here.
Michael Catanzaro
Comment 4 2022-02-23 10:39:57 PST
Comment on attachment 452983 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=452983&action=review > Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp:330 > + if (path == realPath) { Seems this was supposed to be !=, which indicates that another round of testing is warranted here. ;)
Patrick Griffis
Comment 5 2022-02-23 10:57:21 PST
Comment on attachment 452983 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=452983&action=review > Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp:355 > + if (!WTF::String(path).startsWith("/etc/")) No point in making a new object. `g_str_has_prefix()` takes a `char*`.
apteryx
Comment 6 2022-02-23 11:20:37 PST
apteryx
Comment 7 2022-02-23 11:35:16 PST
(In reply to Michael Catanzaro from comment #3) > Comment on attachment 452983 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=452983&action=review > > > Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp:334 > > +static void bindSymlinksRealPath(Vector<CString>& args, const char* path, const char* bindOption = "--ro-bind") > > +{ > > + WTF::String realPath = FileSystem::realPath(path); > > + if (path == realPath) { > > + const char* rpath = realPath.utf8().data(); > > + args.appendVector(Vector<CString>({ bindOption, rpath, rpath })); > > + } > > +} > > I'm a little confused here. > > What I expected: if the path is a symlink, bind its target instead so the > operation doesn't fail. > > What you have here: if the path is a symlink (path != realPath), ignore it. > Sure, the operation will not fail if you skip it, but won't you still wind > up with a broken sandbox? Hmm, you are right. Fixed. > > Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp:352 > > + bindSymlinksRealPath(args, path, bindType); > > + // As /etc is exposed wholesale, do not layer extraneous bind > > Style nit: leave a blank line here. Fixed. Thank you!
Michael Catanzaro
Comment 8 2022-02-23 12:46:37 PST
Comment on attachment 453003 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=453003&action=review OK, almost there... > Source/WebKit/ChangeLog:3 > + Canonicalize source paths passed to bindIfExists in BubbleWrap launcher This line should match the title of the bug: [WPE][GTK] Paths should be canonicalized before calling bwrap > Source/WebKit/ChangeLog:6 > + Reviewed by Michael Catanzaro and Adrian Perez. Please don't fill this out yourself unless you've actually received r+. Just leave it saying NOBODY (OOPS!). Confusing, I know.... > Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp:172 > + const char* rpath = realPath.utf8().data(); > + args.appendVector(Vector<CString>({ bindOption, rpath, rpath })); This is a use-after-free again. The temporary utf8() is out of scope, so rpath is dangling here. You must own the memory somehow. Probably the easiest way is to change rpath to be a CString: CString rpath = realPath.utf8(); args.appendVector(Vector<CString>({ bindOption, rpath.data(), rpath.data() })); I think that would work.
apteryx
Comment 9 2022-02-23 14:12:06 PST
apteryx
Comment 10 2022-02-23 14:14:11 PST
> > > Source/WebKit/ChangeLog:3 > > + Canonicalize source paths passed to bindIfExists in BubbleWrap launcher > > This line should match the title of the bug: > > > [WPE][GTK] Paths should be canonicalized before calling bwrap Fixed. > > Source/WebKit/ChangeLog:6 > > + Reviewed by Michael Catanzaro and Adrian Perez. > > Please don't fill this out yourself unless you've actually received r+. Just > leave it saying NOBODY (OOPS!). Confusing, I know.... OK! I wasn't sure. Fixed. > > Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp:172 > > + const char* rpath = realPath.utf8().data(); > > + args.appendVector(Vector<CString>({ bindOption, rpath, rpath })); > > This is a use-after-free again. The temporary utf8() is out of scope, so > rpath is dangling here. You must own the memory somehow. Probably the > easiest way is to change rpath to be a CString: > > CString rpath = realPath.utf8(); > args.appendVector(Vector<CString>({ bindOption, rpath.data(), rpath.data() > })); > > I think that would work. Tricky! I'm still not sure I fully understand; but I've used your suggestion. Thank you!
Michael Catanzaro
Comment 11 2022-02-23 14:30:26 PST
(In reply to apteryx from comment #10) > Tricky! I'm still not sure I fully understand; but I've used your > suggestion. It's really simple. rpath.utf8() is a CString. rpath.utf8().data() is a pointer to the char* data owned by the CString. It's valid for the lifetime of rpath.utf8(). Once rpath.utf8() is destroyed, it's a dangling pointer to memory that is no longer valid. And in your previous patch, it was destroyed right away, because it was a temporary.
apteryx
Comment 12 2022-02-23 15:03:55 PST
(In reply to Michael Catanzaro from comment #11) > (In reply to apteryx from comment #10) > > Tricky! I'm still not sure I fully understand; but I've used your > > suggestion. > > It's really simple. rpath.utf8() is a CString. rpath.utf8().data() is a > pointer to the char* data owned by the CString. It's valid for the lifetime > of rpath.utf8(). Once rpath.utf8() is destroyed, it's a dangling pointer to > memory that is no longer valid. And in your previous patch, it was destroyed > right away, because it was a temporary. Thank you for having explained in more details... it's clear now!
EWS
Comment 13 2022-02-23 16:50:34 PST
Committed r290401 (247713@main): <https://commits.webkit.org/247713@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 453026 [details].
Philippe Normand
Comment 14 2023-06-30 05:00:55 PDT
Comment on attachment 453026 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=453026&action=review > Source/WebKit/UIProcess/Launcher/glib/BubblewrapLauncher.cpp:173 > + if (path != realPath) { > + CString rpath = realPath.utf8(); > + args.appendVector(Vector<CString>({ bindOption, rpath.data(), rpath.data() })); > + } I don't understand this, path and realPath will be equal if path has no symlink, so path won't be bound at all in the sandbox. Was that really the intent here?
Michael Catanzaro
Comment 15 2023-07-02 07:45:11 PDT
If it's not a symlink then it gets bound at the bottom of bindIfExists, after the call to bindSymlinksRealPath.
Note You need to log in before you can comment on or make changes to this bug.