shr_files fence ftp/sftp;

this fixes GHSA-67rw-2x62-mqqm which is the 2nd season of
e0a92ba72d / CVE-2025-58753
since that only fixed the http / https endpoints
This commit is contained in:
ed
2026-03-10 23:20:11 +00:00
parent 266d6e0ae6
commit 66f1ef6354
4 changed files with 21 additions and 13 deletions

View File

@@ -705,18 +705,22 @@ class VFS(object):
if rem:
ap += "/" + rem
rap = absreal(ap)
rap = ""
if self.shr_files:
assert self.shr_src # !rm
vn, rem = self.shr_src
chk = absreal(os.path.join(vn.realpath, rem))
if chk != rap:
# not the dir itself; assert file allowed
ad, fn = os.path.split(rap)
if chk != ad or fn not in self.shr_files:
return "\n\n"
if rem and rem not in self.shr_files:
return "\n\n"
if resolve:
rap = absreal(ap)
vn, rem = self.shr_src
chk = absreal(os.path.join(vn.realpath, rem))
if chk != rap:
# not the dir itself; assert file allowed
ad, fn = os.path.split(rap)
if chk != ad or fn not in self.shr_files:
return "\n\n"
return rap if resolve else ap
return (rap or absreal(ap)) if resolve else ap
def _dcanonical_shr(self, rem: str) -> str:
"""resolves until the final component (filename)"""

View File

@@ -200,11 +200,13 @@ class FtpFs(AbstractedFS):
cr, cw, cm, cd, _, _, _, _, _ = avfs.uaxs[self.h.uname]
if r and not cr or w and not cw or m and not cm or d and not cd:
raise FSE(t.format(vpath), 1)
else:
ap = vfs.canonical(rem, False)
if "bcasechk" in vfs.flags and not vfs.casechk(rem, True):
raise FSE("No such file or directory", 1)
return os.path.join(vfs.realpath, rem), vfs, rem
return ap, vfs, rem
except Pebkac as ex:
raise FSE(str(ex))

View File

@@ -349,11 +349,13 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
cr, cw, cm, cd, _, _, _, _, _ = avn.uaxs[self.uname]
if r and not cr or w and not cw or m and not cm or d and not cd:
raise OSError(errno.EPERM, "permission denied in [/%s]" % (vpath,))
else:
ap = vn.canonical(rem, False)
if "bcasechk" in vn.flags and not vn.casechk(rem, True):
raise OSError(errno.ENOENT, "file does not exist case-sensitively")
return os.path.join(vn.realpath, rem), vn, rem
return ap, vn, rem
def list_folder(self, path: str) -> list[SATTR] | int:
try:
@@ -484,7 +486,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
try:
vn, rem = self.asrv.vfs.get(vp, self.uname, rd, wr)
ap = os.path.join(vn.realpath, rem)
ap = vn.canonical(rem, False)
vf = vn.flags
except Pebkac as ex:
t = "denied open file [%s], iflag=%s, read=%s, write=%s: %s"

View File

@@ -191,7 +191,7 @@ class SMB(object):
vfs, rem = self.asrv.vfs.get(vpath, uname, *perms)
if not vfs.realpath:
raise Exception("unmapped vfs")
return vfs, vjoin(vfs.realpath, rem)
return vfs, vfs.canonical(rem, False)
def _listdir(self, vpath: str, *a: Any, **ka: Any) -> list[str]:
vpath = vpath.replace("\\", "/").lstrip("/")