Skip to content

Commit f633861

Browse files
committed
fix: Remove conceptually unsound symlink lookup inside extfs
Symlinks can cross FS boundaries
1 parent 47076c1 commit f633861

File tree

7 files changed

+10
-50
lines changed

7 files changed

+10
-50
lines changed

dissect/extfs/extfs.py

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@
3939
class ExtFS:
4040
def __init__(self, fh: BinaryIO):
4141
self.fh = fh
42-
# self._path_cache = {}
4342
self._journal = None
4443

4544
fh.seek(c_ext.EXT2_SBOFF)
@@ -123,13 +122,10 @@ def get(self, path_or_inum: str | int, node: INode | None = None) -> INode:
123122

124123
node = node if node else self.root
125124
parts = path_or_inum.split("/")
126-
for part_num, part in enumerate(parts):
125+
for _, part in enumerate(parts):
127126
if not part:
128127
continue
129128

130-
while node.filetype == stat.S_IFLNK and part_num < len(parts):
131-
node = node.link_inode
132-
133129
for entry in node.iterdir():
134130
if entry.filename == part:
135131
node = entry
@@ -144,13 +140,12 @@ def get_inode(
144140
inum: int,
145141
filename: str | None = None,
146142
filetype: int | None = None,
147-
parentInum: int | None = None,
148143
lazy: bool = False,
149144
) -> INode:
150145
if inum < c_ext.EXT2_BAD_INO or inum > self.sb.s_inodes_count:
151146
raise Error(f"inum out of range {c_ext.EXT2_BAD_INO}-{self.sb.s_inodes_count}: {inum}")
152147

153-
inode = INode(self, inum, filename, filetype, parentInum)
148+
inode = INode(self, inum, filename, filetype)
154149
if not lazy:
155150
inode._inode = inode._read_inode()
156151

@@ -186,11 +181,9 @@ def __init__(
186181
inum: int,
187182
filename: str | None = None,
188183
filetype: int | None = None,
189-
parentInum: int | None = None,
190184
):
191185
self.extfs = extfs
192186
self.inum = inum
193-
self.parentInum = parentInum
194187
self._inode = None
195188

196189
self.filename = filename
@@ -245,17 +238,6 @@ def link(self) -> str:
245238
self._link = self.open().read().decode(errors="surrogateescape")
246239
return self._link
247240

248-
@property
249-
def link_inode(self) -> INode:
250-
if not self._link_inum:
251-
# Relative lookups work because . and .. are actual directory entries
252-
link = self.link
253-
relnode = None if link.startswith("/") else self.extfs.get(self.parentInum)
254-
target = self.extfs.get(self.link, relnode)
255-
self._link_inum = target.inum
256-
return target
257-
return self.extfs.get_inode(self._link_inum)
258-
259241
@property
260242
def xattr(self) -> list[XAttr]:
261243
if not self._xattr:
@@ -364,7 +346,7 @@ def iterdir(self) -> Iterator[INode]:
364346
if ftype:
365347
ftype = FILETYPES[ftype]
366348

367-
yield self.extfs.get_inode(direntry.inode, fname, ftype, parentInum=self.inum, lazy=True)
349+
yield self.extfs.get_inode(direntry.inode, fname, ftype, lazy=True)
368350

369351
offset += direntry.rec_len
370352
buf.seek(offset)

tests/conftest.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,7 @@ def ext4_bin() -> Iterator[BinaryIO]:
2727
@pytest.fixture
2828
def ext4_sparse_bin() -> Iterator[BinaryIO]:
2929
yield from gzip_file("data/ext4_sparse.bin.gz")
30+
31+
@pytest.fixture
32+
def ext4_symlink_bin() -> Iterator[BinaryIO]:
33+
yield from gzip_file("data/ext4_symlink_test.bin.gz")
3.64 KB
Binary file not shown.

tests/data/ext4_symlink_test1.bin.gz

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/data/ext4_symlink_test2.bin.gz

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/data/ext4_symlink_test3.bin.gz

Lines changed: 0 additions & 3 deletions
This file was deleted.

tests/test_ext4.py

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
from __future__ import annotations
22

33
import datetime
4-
import gzip
54
import stat
65
from io import BytesIO
76
from typing import TYPE_CHECKING, BinaryIO
87
from unittest.mock import call, patch
98

10-
import pytest
11-
129
from dissect.extfs.c_ext import c_ext
1310
from dissect.extfs.extfs import EXT4, ExtFS, INode
1411

@@ -80,25 +77,11 @@ def test_sparse(ext4_sparse_bin: BinaryIO) -> None:
8077
assert sparse_all.dataruns() == [(None, 5120)]
8178

8279

83-
@pytest.mark.parametrize(
84-
"image_file",
85-
[
86-
("tests/data/ext4_symlink_test1.bin.gz"),
87-
("tests/data/ext4_symlink_test2.bin.gz"),
88-
("tests/data/ext4_symlink_test3.bin.gz"),
89-
],
90-
)
91-
def test_symlinks(image_file: str) -> None:
80+
def test_symlinks(ext4_symlink_bin: BinaryIO) -> None:
9281
path = "/path/to/dir/with/file.ext"
93-
expect = b"resolved!\n"
94-
95-
def resolve(node: INode) -> INode:
96-
while node.filetype == stat.S_IFLNK:
97-
node = node.link_inode
98-
return node
9982

100-
with gzip.open(image_file, "rb") as disk:
101-
assert resolve(ExtFS(disk).get(path)).open().read() == expect
83+
extfs = ExtFS(ext4_symlink_bin)
84+
assert extfs.get(path).link == "../../../../other/path/source/to/my/file.ext"
10285

10386

10487
@patch("dissect.extfs.extfs.INode.open", return_value=BytesIO(b"\x00" * 16))

0 commit comments

Comments
 (0)