mirror of
https://github.com/9001/copyparty.git
synced 2026-08-16 15:23:08 -06:00
windows: restrict tool paths;
the warning in commit bb40804f2d is still true, but
this makes copyparty slightly safer in environments
where hostile binaries may appear in CWD
This commit is contained in:
parent
bc45299b86
commit
cea97ac6fd
|
|
@ -1727,6 +1727,8 @@ def add_safety(ap):
|
||||||
ap2.add_argument("--loris", metavar="B", type=int, default=60, help="if a client maxes out the server connection limit without sending headers, ban it for \033[33mB\033[0m minutes; disable with [\033[32m0\033[0m]")
|
ap2.add_argument("--loris", metavar="B", type=int, default=60, help="if a client maxes out the server connection limit without sending headers, ban it for \033[33mB\033[0m minutes; disable with [\033[32m0\033[0m]")
|
||||||
ap2.add_argument("--acao", metavar="V[,V]", type=u, default="*", help="Access-Control-Allow-Origin; list of origins (domains/IPs without port) to accept requests from; [\033[32mhttps://1.2.3.4\033[0m]. Default [\033[32m*\033[0m] allows requests from all sites but removes cookies and http-auth; only ?pw=hunter2 survives")
|
ap2.add_argument("--acao", metavar="V[,V]", type=u, default="*", help="Access-Control-Allow-Origin; list of origins (domains/IPs without port) to accept requests from; [\033[32mhttps://1.2.3.4\033[0m]. Default [\033[32m*\033[0m] allows requests from all sites but removes cookies and http-auth; only ?pw=hunter2 survives")
|
||||||
ap2.add_argument("--acam", metavar="V[,V]", type=u, default="GET,HEAD", help="Access-Control-Allow-Methods; list of methods to accept from offsite ('*' behaves like \033[33m--acao\033[0m's description)")
|
ap2.add_argument("--acam", metavar="V[,V]", type=u, default="GET,HEAD", help="Access-Control-Allow-Methods; list of methods to accept from offsite ('*' behaves like \033[33m--acao\033[0m's description)")
|
||||||
|
if FULL_HELP or ANYWIN:
|
||||||
|
ap2.add_argument("--unsafe-tools", action="store_true", help="windows-only: allow running programs (ffmpeg, dcraw_emu, ...) when their location is inside a folder that can be uploaded to (dangerous due to DLL-hijacking)")
|
||||||
if FULL_HELP or (not ANYWIN and not UNIX):
|
if FULL_HELP or (not ANYWIN and not UNIX):
|
||||||
ap2.add_argument("--th-bwrap", metavar="CMD", type=u, default=th_bwrap, help="optional bwrap sandbox command for FFmpeg and dcraw (Linux-only)")
|
ap2.add_argument("--th-bwrap", metavar="CMD", type=u, default=th_bwrap, help="optional bwrap sandbox command for FFmpeg and dcraw (Linux-only)")
|
||||||
ap2.add_argument("--use-bwrap", metavar="TXT", type=u, default="n", help="a/n/f; [\033[32ma\033[0m]=auto (yes if the program 'bwrap' exists (assumes it works)), [\033[32mn\033[0m]=no (assumes bwrap is broken), [\033[32mf\033[0m]=force (disables FFmpeg if bwrap unavailable)")
|
ap2.add_argument("--use-bwrap", metavar="TXT", type=u, default="n", help="a/n/f; [\033[32ma\033[0m]=auto (yes if the program 'bwrap' exists (assumes it works)), [\033[32mn\033[0m]=no (assumes bwrap is broken), [\033[32mf\033[0m]=force (disables FFmpeg if bwrap unavailable)")
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@ from .util import (
|
||||||
FFMPEG_URL,
|
FFMPEG_URL,
|
||||||
LOG,
|
LOG,
|
||||||
REKOBO_LKEY,
|
REKOBO_LKEY,
|
||||||
|
SCWD,
|
||||||
VF_CAREFUL,
|
VF_CAREFUL,
|
||||||
|
absreal,
|
||||||
expand_osenv_c,
|
expand_osenv_c,
|
||||||
fsenc,
|
fsenc,
|
||||||
gzip,
|
gzip,
|
||||||
|
|
@ -47,10 +49,10 @@ except:
|
||||||
HAVE_MUTAGEN = False
|
HAVE_MUTAGEN = False
|
||||||
|
|
||||||
|
|
||||||
def have_ff(name: str) -> bytes:
|
def have_ff(name: str) -> list[bytes]:
|
||||||
uname = name.upper()
|
uname = name.upper()
|
||||||
if os.environ.get("PRTY_NO_" + uname):
|
if os.environ.get("PRTY_NO_" + uname):
|
||||||
return b""
|
return []
|
||||||
|
|
||||||
ebin = os.environ.get("PRTY_%s_BIN" % (uname,))
|
ebin = os.environ.get("PRTY_%s_BIN" % (uname,))
|
||||||
try:
|
try:
|
||||||
|
|
@ -66,11 +68,12 @@ def have_ff(name: str) -> bytes:
|
||||||
bcmd = scmd.encode("utf-8")
|
bcmd = scmd.encode("utf-8")
|
||||||
try:
|
try:
|
||||||
sp.Popen([bcmd, b"-version"], stdout=sp.PIPE, stderr=sp.PIPE).communicate()
|
sp.Popen([bcmd, b"-version"], stdout=sp.PIPE, stderr=sp.PIPE).communicate()
|
||||||
return bcmd
|
return [bcmd]
|
||||||
except:
|
except:
|
||||||
return b""
|
return []
|
||||||
else:
|
else:
|
||||||
return (shutil.which(scmd) or "").encode("utf-8")
|
ret = shutil.which(scmd)
|
||||||
|
return [absreal(ret).encode("utf-8")] if ret else []
|
||||||
|
|
||||||
|
|
||||||
HAVE_FFMPEG = have_ff("ffmpeg")
|
HAVE_FFMPEG = have_ff("ffmpeg")
|
||||||
|
|
@ -247,14 +250,14 @@ def ffprobe(
|
||||||
) -> tuple[dict[str, tuple[int, Any]], dict[str, list[Any]], list[Any], dict[str, Any]]:
|
) -> tuple[dict[str, tuple[int, Any]], dict[str, list[Any]], list[Any], dict[str, Any]]:
|
||||||
# ffprobe -hide_banner -show_streams -show_format --
|
# ffprobe -hide_banner -show_streams -show_format --
|
||||||
bap = fsenc(abspath)
|
bap = fsenc(abspath)
|
||||||
cmd = bwrap(HAVE_FFPROBE, bap, b"") + [
|
cmd = bwrap(HAVE_FFPROBE[0], bap, b"") + [
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
b"-show_streams",
|
b"-show_streams",
|
||||||
b"-show_format",
|
b"-show_format",
|
||||||
b"--",
|
b"--",
|
||||||
bap,
|
bap,
|
||||||
]
|
]
|
||||||
rc, so, se = runcmd(cmd, timeout=timeout, nice=True, oom=200)
|
rc, so, se = runcmd(cmd, cwd=SCWD, timeout=timeout, nice=True, oom=200)
|
||||||
if rc and TH_BWRAP:
|
if rc and TH_BWRAP:
|
||||||
bwrap_fail(se)
|
bwrap_fail(se)
|
||||||
retchk(rc, cmd, se)
|
retchk(rc, cmd, se)
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ from .util import (
|
||||||
alltrace,
|
alltrace,
|
||||||
build_netmap,
|
build_netmap,
|
||||||
expat_ver,
|
expat_ver,
|
||||||
|
fsenc,
|
||||||
gzip,
|
gzip,
|
||||||
html_escape,
|
html_escape,
|
||||||
load_ipr,
|
load_ipr,
|
||||||
|
|
@ -400,6 +401,9 @@ class SvcHub(object):
|
||||||
self.asrv = AuthSrv(self.args, self.log, dargs=self.dargs)
|
self.asrv = AuthSrv(self.args, self.log, dargs=self.dargs)
|
||||||
ramdisk_chk(self.asrv)
|
ramdisk_chk(self.asrv)
|
||||||
|
|
||||||
|
if ANYWIN and not self.args.unsafe_tools:
|
||||||
|
self._check_toolpaths()
|
||||||
|
|
||||||
if args.cgen:
|
if args.cgen:
|
||||||
self.asrv.cgen()
|
self.asrv.cgen()
|
||||||
|
|
||||||
|
|
@ -1025,6 +1029,18 @@ class SvcHub(object):
|
||||||
if zb:
|
if zb:
|
||||||
Daemon(self.s6_notify, "s6-notify", (zb,))
|
Daemon(self.s6_notify, "s6-notify", (zb,))
|
||||||
|
|
||||||
|
def _check_toolpaths(self) -> None:
|
||||||
|
for vol in self.asrv.vfs.all_vols.values():
|
||||||
|
if not vol.realpath or not vol.axs.uwrite:
|
||||||
|
continue
|
||||||
|
ap_vol = (vol.realpath + os.sep).encode("utf-8")
|
||||||
|
for zsl in (HAVE_FFMPEG, HAVE_FFPROBE, HAVE_DCRAW):
|
||||||
|
if zsl and zsl[0].startswith(ap_vol):
|
||||||
|
zs = zsl[0].decode("utf-8", "replace")
|
||||||
|
t = "will not use [%s] because it is inside a writable volume [/%s] => [%s] and --unsafe-tools is not enabled"
|
||||||
|
self.log("root", t % (zs, vol.vpath, vol.realpath), 3)
|
||||||
|
del zsl[0]
|
||||||
|
|
||||||
def _feature_test(self) -> None:
|
def _feature_test(self) -> None:
|
||||||
fok = []
|
fok = []
|
||||||
fng = []
|
fng = []
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ from .mtag import (
|
||||||
from .util import BytesIO # type: ignore
|
from .util import BytesIO # type: ignore
|
||||||
from .util import (
|
from .util import (
|
||||||
FFMPEG_URL,
|
FFMPEG_URL,
|
||||||
|
SCWD,
|
||||||
VF_CAREFUL,
|
VF_CAREFUL,
|
||||||
Cooldown,
|
Cooldown,
|
||||||
Daemon,
|
Daemon,
|
||||||
|
|
@ -774,7 +775,7 @@ class ThumbSrv(object):
|
||||||
self.wait4ram(0.6, tpath)
|
self.wait4ram(0.6, tpath)
|
||||||
bap = fsenc(abspath)
|
bap = fsenc(abspath)
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_DCRAW, bap, b"") + [
|
cmd = bwrap(HAVE_DCRAW[0], bap, b"") + [
|
||||||
b"-h", # halfsize
|
b"-h", # halfsize
|
||||||
b"-o", b"1", # srgb
|
b"-o", b"1", # srgb
|
||||||
b"-s", b"0", # first frame
|
b"-s", b"0", # first frame
|
||||||
|
|
@ -782,7 +783,7 @@ class ThumbSrv(object):
|
||||||
bap,
|
bap,
|
||||||
]
|
]
|
||||||
# fmt: on
|
# fmt: on
|
||||||
p = sp.Popen(cmd, stdout=sp.PIPE)
|
p = sp.Popen(cmd, stdout=sp.PIPE, cwd=SCWD)
|
||||||
try:
|
try:
|
||||||
if HAVE_PIL:
|
if HAVE_PIL:
|
||||||
self.conv_image_pil(Image.open(p.stdout), tpath, fmt, vn)
|
self.conv_image_pil(Image.open(p.stdout), tpath, fmt, vn)
|
||||||
|
|
@ -877,7 +878,7 @@ class ThumbSrv(object):
|
||||||
bap_in = fsenc(abspath)
|
bap_in = fsenc(abspath)
|
||||||
bap_out = fsenc(tpath)
|
bap_out = fsenc(tpath)
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
cmd = bwrap(HAVE_FFMPEG[0], bap_in, bap_out) + [
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner"
|
b"-hide_banner"
|
||||||
|
|
@ -918,7 +919,7 @@ class ThumbSrv(object):
|
||||||
|
|
||||||
def _run_ff(self, cmd: list[bytes], vn: VFS, kto: str, oom: int = 400) -> None:
|
def _run_ff(self, cmd: list[bytes], vn: VFS, kto: str, oom: int = 400) -> None:
|
||||||
# self.log((b" ".join(cmd)).decode("utf-8"))
|
# self.log((b" ".join(cmd)).decode("utf-8"))
|
||||||
ret, _, serr = runcmd(cmd, timeout=vn.flags[kto], nice=True, oom=oom)
|
ret, _, serr = runcmd(cmd, cwd=SCWD, timeout=vn.flags[kto], nice=True, oom=oom)
|
||||||
if not ret:
|
if not ret:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -1020,7 +1021,7 @@ class ThumbSrv(object):
|
||||||
bap_out = fsenc(tpath)
|
bap_out = fsenc(tpath)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
cmd = bwrap(HAVE_FFMPEG[0], bap_in, bap_out) + [
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
|
|
@ -1101,7 +1102,7 @@ class ThumbSrv(object):
|
||||||
bap_out = fsenc(infile)
|
bap_out = fsenc(infile)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
cmd = bwrap(HAVE_FFMPEG[0], bap_in, bap_out) + [
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
|
|
@ -1135,7 +1136,7 @@ class ThumbSrv(object):
|
||||||
bap_out = fsenc(tpath)
|
bap_out = fsenc(tpath)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
cmd = bwrap(HAVE_FFMPEG[0], bap_in, bap_out) + [
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
|
|
@ -1173,7 +1174,7 @@ class ThumbSrv(object):
|
||||||
# to not support opus then it's probably also super picky
|
# to not support opus then it's probably also super picky
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
cmd = bwrap(HAVE_FFMPEG[0], bap_in, bap_out) + [
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
|
|
@ -1204,7 +1205,7 @@ class ThumbSrv(object):
|
||||||
bap_out = fsenc(tpath)
|
bap_out = fsenc(tpath)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
cmd = bwrap(HAVE_FFMPEG[0], bap_in, bap_out) + [
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
|
|
@ -1241,7 +1242,7 @@ class ThumbSrv(object):
|
||||||
bap_out = fsenc(tpath)
|
bap_out = fsenc(tpath)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
cmd = bwrap(HAVE_FFMPEG[0], bap_in, bap_out) + [
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
|
|
@ -1304,7 +1305,7 @@ class ThumbSrv(object):
|
||||||
bap_out = fsenc(tpath)
|
bap_out = fsenc(tpath)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
cmd = bwrap(HAVE_FFMPEG[0], bap_in, bap_out) + [
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
|
|
@ -1347,7 +1348,7 @@ class ThumbSrv(object):
|
||||||
bap_out = fsenc(tmp_opus)
|
bap_out = fsenc(tmp_opus)
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
cmd = bwrap(HAVE_FFMPEG[0], bap_in, bap_out) + [
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
|
|
@ -1374,7 +1375,7 @@ class ThumbSrv(object):
|
||||||
bap_in = fsenc(abspath)
|
bap_in = fsenc(abspath)
|
||||||
bap_out = fsenc(tpath)
|
bap_out = fsenc(tpath)
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
cmd = bwrap(HAVE_FFMPEG[0], bap_in, bap_out) + [
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
|
|
@ -1396,7 +1397,7 @@ class ThumbSrv(object):
|
||||||
bap_in = fsenc(tmp_opus)
|
bap_in = fsenc(tmp_opus)
|
||||||
bap_out = fsenc(tpath)
|
bap_out = fsenc(tpath)
|
||||||
# fmt: off
|
# fmt: off
|
||||||
cmd = bwrap(HAVE_FFMPEG, bap_in, bap_out) + [
|
cmd = bwrap(HAVE_FFMPEG[0], bap_in, bap_out) + [
|
||||||
b"-nostdin",
|
b"-nostdin",
|
||||||
b"-v", b"error",
|
b"-v", b"error",
|
||||||
b"-hide_banner",
|
b"-hide_banner",
|
||||||
|
|
|
||||||
|
|
@ -678,6 +678,12 @@ except:
|
||||||
HAVE_BWRAP = ""
|
HAVE_BWRAP = ""
|
||||||
|
|
||||||
|
|
||||||
|
if ANYWIN:
|
||||||
|
SCWD = os.environ["systemroot"]
|
||||||
|
else:
|
||||||
|
SCWD = None
|
||||||
|
|
||||||
|
|
||||||
def py_desc() -> str:
|
def py_desc() -> str:
|
||||||
interp = platform.python_implementation()
|
interp = platform.python_implementation()
|
||||||
py_ver = ".".join([str(x) for x in sys.version_info])
|
py_ver = ".".join([str(x) for x in sys.version_info])
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue