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,9 +705,13 @@ class VFS(object):
if rem: if rem:
ap += "/" + rem ap += "/" + rem
rap = absreal(ap) rap = ""
if self.shr_files: if self.shr_files:
assert self.shr_src # !rm assert self.shr_src # !rm
if rem and rem not in self.shr_files:
return "\n\n"
if resolve:
rap = absreal(ap)
vn, rem = self.shr_src vn, rem = self.shr_src
chk = absreal(os.path.join(vn.realpath, rem)) chk = absreal(os.path.join(vn.realpath, rem))
if chk != rap: if chk != rap:
@ -716,7 +720,7 @@ class VFS(object):
if chk != ad or fn not in self.shr_files: if chk != ad or fn not in self.shr_files:
return "\n\n" 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: def _dcanonical_shr(self, rem: str) -> str:
"""resolves until the final component (filename)""" """resolves until the final component (filename)"""

View file

@ -200,11 +200,13 @@ class FtpFs(AbstractedFS):
cr, cw, cm, cd, _, _, _, _, _ = avfs.uaxs[self.h.uname] 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: 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) raise FSE(t.format(vpath), 1)
else:
ap = vfs.canonical(rem, False)
if "bcasechk" in vfs.flags and not vfs.casechk(rem, True): if "bcasechk" in vfs.flags and not vfs.casechk(rem, True):
raise FSE("No such file or directory", 1) 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: except Pebkac as ex:
raise FSE(str(ex)) raise FSE(str(ex))

View file

@ -349,11 +349,13 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
cr, cw, cm, cd, _, _, _, _, _ = avn.uaxs[self.uname] 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: 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,)) 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): if "bcasechk" in vn.flags and not vn.casechk(rem, True):
raise OSError(errno.ENOENT, "file does not exist case-sensitively") 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: def list_folder(self, path: str) -> list[SATTR] | int:
try: try:
@ -484,7 +486,7 @@ class SFTP_Srv(paramiko.SFTPServerInterface):
try: try:
vn, rem = self.asrv.vfs.get(vp, self.uname, rd, wr) 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 vf = vn.flags
except Pebkac as ex: except Pebkac as ex:
t = "denied open file [%s], iflag=%s, read=%s, write=%s: %s" 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) vfs, rem = self.asrv.vfs.get(vpath, uname, *perms)
if not vfs.realpath: if not vfs.realpath:
raise Exception("unmapped vfs") 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]: def _listdir(self, vpath: str, *a: Any, **ka: Any) -> list[str]:
vpath = vpath.replace("\\", "/").lstrip("/") vpath = vpath.replace("\\", "/").lstrip("/")