Skip to content

Commit

Permalink
fix: xattr table index to split position into decompressed and compre…
Browse files Browse the repository at this point in the history
…ssed offset
  • Loading branch information
jonathongardner committed Jan 17, 2025
1 parent 31082f1 commit 0442ace
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 17 deletions.
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) {
// 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

0 comments on commit 0442ace

Please sign in to comment.