Skip to content

Commit d59ec4c

Browse files
committed
Filter out problematic file URLs
Change-Id: I87fd37e56326bef4888354b923407530c6f70760 Reviewed-on: https://gerrit.libreoffice.org/70177 Tested-by: Jenkins Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
1 parent 3b41abe commit d59ec4c

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

shell/source/unix/exec/shellexec.cxx

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
#include <errno.h>
4444
#include <unistd.h>
4545

46+
#if defined MACOSX
47+
#include <sys/stat.h>
48+
#endif
49+
4650
using com::sun::star::system::XSystemShellExecute;
4751
using com::sun::star::system::SystemShellExecuteException;
4852

@@ -113,6 +117,39 @@ void SAL_CALL ShellExec::execute( const OUString& aCommand, const OUString& aPar
113117
}
114118

115119
#ifdef MACOSX
120+
if (uri->getScheme().equalsIgnoreAsciiCase("file")) {
121+
OUString pathname;
122+
auto const e1 = osl::FileBase::getSystemPathFromFileURL(aCommand, pathname);
123+
if (e1 != osl::FileBase::E_None) {
124+
throw css::lang::IllegalArgumentException(
125+
("XSystemShellExecute.execute, getSystemPathFromFileURL <" + aCommand
126+
+ "> failed with " + OUString::number(e1)),
127+
{}, 0);
128+
}
129+
OString pathname8;
130+
if (!pathname.convertToString(
131+
&pathname8, RTL_TEXTENCODING_UTF8,
132+
(RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR
133+
| RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR)))
134+
{
135+
throw css::lang::IllegalArgumentException(
136+
"XSystemShellExecute.execute, cannot convert \"" + pathname + "\" to UTF-8", {},
137+
0);
138+
}
139+
struct stat st;
140+
auto const e2 = stat(pathname8.getStr(), &st);
141+
if (e2 != 0) {
142+
auto const e3 = errno;
143+
SAL_INFO("shell", "stat(" << pathname8 << ") failed with errno " << e3);
144+
}
145+
if (e2 != 0 || !S_ISREG(st.st_mode)
146+
|| (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)
147+
{
148+
throw css::lang::IllegalArgumentException(
149+
"XSystemShellExecute.execute, cannot process <" + aCommand + ">", {}, 0);
150+
}
151+
}
152+
116153
//TODO: Using open(1) with an argument that syntactically is an absolute
117154
// URI reference does not necessarily give expected results:
118155
// 1 If the given URI reference matches a supported scheme (e.g.,

shell/source/win32/SysShExec.cxx

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@
1818
*/
1919

2020
#include <algorithm>
21+
#include <cassert>
2122

2223
#include <osl/diagnose.h>
24+
#include <osl/process.h>
2325
#include <sal/log.hxx>
2426
#include "SysShExec.hxx"
2527
#include <osl/file.hxx>
@@ -30,12 +32,16 @@
3032
#include <com/sun/star/uri/UriReferenceFactory.hpp>
3133
#include <cppuhelper/supportsservice.hxx>
3234
#include <o3tl/char16_t2wchar_t.hxx>
35+
#include <o3tl/runtimetooustring.hxx>
3336

3437
#define WIN32_LEAN_AND_MEAN
3538
#include <windows.h>
3639
#include <shellapi.h>
40+
#include <Shobjidl.h>
3741
#include <objbase.h>
3842

43+
#include <systools/win32/comtools.hxx>
44+
3945
using com::sun::star::uno::Reference;
4046
using com::sun::star::uno::RuntimeException;
4147
using com::sun::star::uno::Sequence;
@@ -242,6 +248,18 @@ CSysShExec::CSysShExec( const Reference< css::uno::XComponentContext >& xContext
242248

243249
namespace
244250
{
251+
bool checkExtension(OUString const & extension, OUString const & blacklist) {
252+
assert(!extension.isEmpty());
253+
for (sal_Int32 i = 0; i != -1;) {
254+
OUString tok = blacklist.getToken(0, ';', i);
255+
tok.startsWith(".", &tok);
256+
if (extension.equalsIgnoreAsciiCase(tok)) {
257+
return false;
258+
}
259+
}
260+
return true;
261+
}
262+
245263
// This callback checks if the found window is the specified process's top-level window,
246264
// and activates the first found such window.
247265
BOOL CALLBACK FindAndActivateProcWnd(HWND hwnd, LPARAM lParam)
@@ -295,6 +313,102 @@ void SAL_CALL CSysShExec::execute( const OUString& aCommand, const OUString& aPa
295313
+ aCommand,
296314
static_cast< cppu::OWeakObject * >(this), 0);
297315
}
316+
if (uri->getScheme().equalsIgnoreAsciiCase("file")) {
317+
OUString pathname;
318+
auto const e1 = osl::FileBase::getSystemPathFromFileURL(aCommand, pathname);
319+
if (e1 != osl::FileBase::E_None) {
320+
throw css::lang::IllegalArgumentException(
321+
("XSystemShellExecute.execute, getSystemPathFromFileURL <" + aCommand
322+
+ "> failed with " + OUString::number(e1)),
323+
{}, 0);
324+
}
325+
for (int i = 0;; ++i) {
326+
SHFILEINFOW info;
327+
if (SHGetFileInfoW(
328+
o3tl::toW(pathname.getStr()), 0, &info, sizeof info, SHGFI_EXETYPE)
329+
!= 0)
330+
{
331+
throw css::lang::IllegalArgumentException(
332+
"XSystemShellExecute.execute, cannot process <" + aCommand + ">", {}, 0);
333+
}
334+
if (SHGetFileInfoW(
335+
o3tl::toW(pathname.getStr()), 0, &info, sizeof info, SHGFI_ATTRIBUTES)
336+
== 0)
337+
{
338+
throw css::lang::IllegalArgumentException(
339+
"XSystemShellExecute.execute, SHGetFileInfoW(" + pathname + ") failed", {},
340+
0);
341+
}
342+
if ((info.dwAttributes & SFGAO_LINK) == 0) {
343+
break;
344+
}
345+
sal::systools::COMReference<IShellLinkW> link;
346+
auto e2 = CoCreateInstance(
347+
CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLinkW,
348+
reinterpret_cast<LPVOID *>(&link));
349+
if (FAILED(e2)) {
350+
throw css::lang::IllegalArgumentException(
351+
("XSystemShellExecute.execute, CoCreateInstance failed with "
352+
+ OUString::number(e2)),
353+
{}, 0);
354+
}
355+
sal::systools::COMReference<IPersistFile> file;
356+
try {
357+
file = link.QueryInterface<IPersistFile>(IID_IPersistFile);
358+
} catch(sal::systools::ComError & e3) {
359+
throw css::lang::IllegalArgumentException(
360+
("XSystemShellExecute.execute, QueryInterface failed with: "
361+
+ o3tl::runtimeToOUString(e3.what())),
362+
{}, 0);
363+
}
364+
e2 = file->Load(o3tl::toW(pathname.getStr()), STGM_READ);
365+
if (FAILED(e2)) {
366+
throw css::lang::IllegalArgumentException(
367+
("XSystemShellExecute.execute, IPersistFile.Load failed with "
368+
+ OUString::number(e2)),
369+
{}, 0);
370+
}
371+
e2 = link->Resolve(nullptr, SLR_UPDATE | SLR_NO_UI);
372+
if (FAILED(e2)) {
373+
throw css::lang::IllegalArgumentException(
374+
("XSystemShellExecute.execute, IShellLink.Resolve failed with "
375+
+ OUString::number(e2)),
376+
{}, 0);
377+
}
378+
wchar_t path[MAX_PATH];
379+
WIN32_FIND_DATAW wfd;
380+
e2 = link->GetPath(path, MAX_PATH, &wfd, SLGP_RAWPATH);
381+
if (FAILED(e2)) {
382+
throw css::lang::IllegalArgumentException(
383+
("XSystemShellExecute.execute, IShellLink.GetPath failed with "
384+
+ OUString::number(e2)),
385+
{}, 0);
386+
}
387+
pathname = o3tl::toU(path);
388+
// Fail at some arbitrary nesting depth, to avoid an infinite loop:
389+
if (i == 30) {
390+
throw css::lang::IllegalArgumentException(
391+
"XSystemShellExecute.execute, link depth exceeded for <" + aCommand + ">",
392+
{}, 0);
393+
}
394+
}
395+
auto const n = pathname.lastIndexOf('.');
396+
if (n > pathname.lastIndexOf('\\')) {
397+
auto const ext = pathname.copy(n + 1);
398+
OUString env;
399+
if (osl_getEnvironment(OUString("PATHEXT").pData, &env.pData) != osl_Process_E_None)
400+
{
401+
SAL_INFO("shell", "osl_getEnvironment(PATHEXT) failed");
402+
}
403+
if (!(checkExtension(ext, env)
404+
&& checkExtension(
405+
ext, ".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC;.PY")))
406+
{
407+
throw css::lang::IllegalArgumentException(
408+
"XSystemShellExecute.execute, cannot process <" + aCommand + ">", {}, 0);
409+
}
410+
}
411+
}
298412
}
299413

300414
/* #i4789#; jump mark detection on system paths

0 commit comments

Comments
 (0)