Skip to content

fix: xattr table index to split position into decompressed and compressed offset #277

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions filesystem/squashfs/const_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,12 @@ func testGetFilesystem(f fs.File) (*FileSystem, []byte, error) {
return testFs, b, nil
}

func testGetInodeMetabytes() (inodeBytes []byte, inodesStart uint64, err error) {
func testGetInodeMetabytes() (inodeBytes []byte, err error) {
testFs, b, err := testGetFilesystem(nil)
if err != nil {
return nil, 0, err
return nil, err
}
return b[testFs.superblock.inodeTableStart+2:], testFs.superblock.inodeTableStart, nil
return b[testFs.superblock.inodeTableStart+2:], nil
}

//nolint:deadcode // we need these references in the future
Expand Down
12 changes: 6 additions & 6 deletions filesystem/squashfs/inode_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func TestInodeSize(t *testing.T) {
}

func TestInodeHeader(t *testing.T) {
b, _, err := testGetInodeMetabytes()
b, err := testGetInodeMetabytes()
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -142,7 +142,7 @@ func TestBlockData(t *testing.T) {

func TestBasicDirectory(t *testing.T) {
dir := testBasicDirectory
b, _, err := testGetInodeMetabytes()
b, err := testGetInodeMetabytes()
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -203,7 +203,7 @@ func TestExtendedDirectory(t *testing.T) {

func TestBasicFile(t *testing.T) {
f := testBasicFile
b, _, err := testGetInodeMetabytes()
b, err := testGetInodeMetabytes()
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -279,7 +279,7 @@ func TestBasicFile(t *testing.T) {
func TestExtendedFile(t *testing.T) {
fd := testExtendedFile
f := &fd
b, _, err := testGetInodeMetabytes()
b, err := testGetInodeMetabytes()
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -332,7 +332,7 @@ func TestExtendedFile(t *testing.T) {

func TestBasicSymlink(t *testing.T) {
s := testBasicSymlink
b, _, err := testGetInodeMetabytes()
b, err := testGetInodeMetabytes()
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -430,7 +430,7 @@ func TestExtendedIPC(t *testing.T) {
}

func TestInode(t *testing.T) {
b, _, err := testGetInodeMetabytes()
b, err := testGetInodeMetabytes()
if err != nil {
t.Fatal(err)
}
Expand Down
10 changes: 6 additions & 4 deletions filesystem/squashfs/squashfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -809,30 +809,32 @@ func readXattrsTable(s *superblock, file backend.File, c Compressor) (*xAttrTabl
// now load the actual xAttrs data
xAttrEnd := binary.LittleEndian.Uint64(b[:8])
xAttrData := make([]byte, 0)
offsetMap := map[uint32]uint32{0: 0}
for i := xAttrStart; i < xAttrEnd; {
uncompressed, size, err = fs.readMetaBlock(file, c, int64(i))
if err != nil {
return nil, fmt.Errorf("error reading xattr data meta block at position %d: %v", i, err)
}
xAttrData = append(xAttrData, uncompressed...)
i += uint64(size)
offsetMap[uint32(i-xAttrStart)] = uint32(len(xAttrData))
}

// now have all of the indexes and metadata loaded
// need to pass it the offset of the beginning of the id table from the beginning of the disk
return parseXattrsTable(xAttrData, bIndex, s.idTableStart, c)
return parseXattrsTable(xAttrData, bIndex, offsetMap, c)
}

//nolint:unparam,unused,revive // this does not use offset or compressor yet, but only because we have not yet added support
func parseXattrsTable(bUIDXattr, bIndex []byte, offset uint64, c Compressor) (*xAttrTable, error) {
//nolint:unparam,unused,revive // this does not use compressor yet, but only because we have not yet added support
func parseXattrsTable(bUIDXattr, bIndex []byte, offsetMap map[uint32]uint32, c Compressor) (*xAttrTable, error) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure if this was the plan for offset but I replaced it

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is better. You can see the comment. Does it no longer need the nolint comments? Or is c Compressor still unused?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah Compressor is still unused, I can remove it if you want

// create the ID list
var (
xAttrIDList []*xAttrIndex
)

entrySize := int(xAttrIDEntrySize)
for i := 0; i+entrySize <= len(bIndex); i += entrySize {
entry, err := parseXAttrIndex(bIndex[i:])
entry, err := parseXAttrIndex(bIndex[i:], offsetMap)
if err != nil {
return nil, fmt.Errorf("error parsing xAttr ID table entry in position %d: %v", i, err)
}
Expand Down
4 changes: 2 additions & 2 deletions filesystem/squashfs/squashfs_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func TestValidateBlocksize(t *testing.T) {

func TestParseXAttrsTable(t *testing.T) {
// parseXattrsTable(bUIDXattr, bIndex []byte, offset uint64, c compressor) (*xAttrTable, error) {
b, offset, err := testGetInodeMetabytes()
b, err := testGetInodeMetabytes()
if err != nil {
t.Fatalf("error getting metadata bytes: %v", err)
}
Expand All @@ -81,7 +81,7 @@ func TestParseXAttrsTable(t *testing.T) {

// entries in the xattr ID table are offset from beginning of disk, not from xattr table
// so need offset of bUIDXattr from beginning of disk to make use of it
table, err := parseXattrsTable(bUIDXattr, bIndex, offset+startUID, nil)
table, err := parseXattrsTable(bUIDXattr, bIndex, map[uint32]uint32{0: 0}, nil)
if err != nil {
t.Fatalf("error reading xattrs table: %v", err)
}
Expand Down
19 changes: 15 additions & 4 deletions filesystem/squashfs/xattr.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,23 @@ type xAttrIndex struct {
size uint32
}

func parseXAttrIndex(b []byte) (*xAttrIndex, error) {
func parseXAttrIndex(b []byte, offsetMap map[uint32]uint32) (*xAttrIndex, error) {
if len(b) < int(xAttrIDEntrySize) {
return nil, fmt.Errorf("cannot parse xAttr Index of size %d less than minimum %d", len(b), xAttrIDEntrySize)
}
return &xAttrIndex{
pos: binary.LittleEndian.Uint64(b[0:8]),

offsetKey := binary.LittleEndian.Uint32(b[2:6])
offset, ok := offsetMap[offsetKey]
if !ok {
return nil, fmt.Errorf("cannot parse xAttr Index invalid offset key %d", offsetKey)
}
toReturn := &xAttrIndex{
pos: uint64(binary.LittleEndian.Uint16(b[0:2])) + uint64(offset),
count: binary.LittleEndian.Uint32(b[8:12]),
size: binary.LittleEndian.Uint32(b[12:16]),
}, nil
}

return toReturn, nil
}

type xAttrTable struct {
Expand All @@ -39,6 +47,9 @@ func (x *xAttrTable) find(pos int) (map[string]string, error) {
return nil, fmt.Errorf("position %d is greater than list size %d", pos, len(x.list))
}
entry := x.list[pos]
if int(entry.pos) >= len(x.data) {
return nil, fmt.Errorf("entry position %d is greater than list size %d", entry.pos, len(x.data))
}
b := x.data[entry.pos:]
count := entry.count
ptr := 0
Expand Down
34 changes: 27 additions & 7 deletions filesystem/squashfs/xattr_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,43 @@ import (
func TestParseXAttrIndex(t *testing.T) {
tests := []struct {
b []byte
o map[uint32]uint32
x *xAttrIndex
err error
}{
{[]byte{0x0, 0x1}, nil, fmt.Errorf("cannot parse xAttr Index of size %d less than minimum %d", 2, xAttrIDEntrySize)},
{[]byte{0x0, 0x1}, map[uint32]uint32{0: 0}, nil, fmt.Errorf("cannot parse xAttr Index of size %d less than minimum %d", 2, xAttrIDEntrySize)},
{[]byte{
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb,
0xc, 0xd, 0xe, 0xf,
0x10, 0x11, 0x12, 0x13, 0x14},
0x0, 0x1, // position in decompressed
0x2, 0x3, 0x4, 0x5, // offset of compressed data
0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14},
map[uint32]uint32{},
nil, fmt.Errorf("cannot parse xAttr Index invalid offset key %d", 84148994)},
{[]byte{
0x0, 0x1, // position in decompressed
0x2, 0x3, 0x4, 0x5, // offset of compressed data
0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14},
map[uint32]uint32{84148994: 5},
&xAttrIndex{
pos: 261,
count: 0x0b0a0908,
size: 0x0f0e0d0c,
}, nil},
{[]byte{
0x0, 0x1, // position in decompressed
0x2, 0x0, 0x0, 0x0, // offset of compressed data
0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd,
0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14},
map[uint32]uint32{2: 0},
&xAttrIndex{
pos: 0x0706050403020100,
pos: 256,
count: 0x0b0a0908,
size: 0x0f0e0d0c,
}, nil},
}
for i, tt := range tests {
x, err := parseXAttrIndex(tt.b)
x, err := parseXAttrIndex(tt.b, tt.o)
switch {
case (err == nil && tt.err != nil) || (err != nil && tt.err == nil) || (err != nil && tt.err != nil && !strings.HasPrefix(err.Error(), tt.err.Error())):
t.Errorf("%d: mismatched error, actual then expected", i)
Expand Down
Loading