Skip to content

Commit 7c81932

Browse files
committed
fix(cpio+xar): harden entry names against path traversal
1 parent e4a72ee commit 7c81932

File tree

2 files changed

+35
-3
lines changed

2 files changed

+35
-3
lines changed

pkg/cpio/cpio.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"io"
77
"io/fs"
88
"os"
9+
"path"
910
"strings"
1011
"time"
1112
)
@@ -128,6 +129,17 @@ func parseOctal(b []byte) uint64 {
128129
return sum
129130
}
130131

132+
func sanitizeArchiveName(name string) (string, error) {
133+
cleaned := path.Clean(name)
134+
if cleaned == "." {
135+
return "", fmt.Errorf("cpio: invalid path %q", name)
136+
}
137+
if cleaned == ".." || strings.HasPrefix(cleaned, "../") {
138+
return "", fmt.Errorf("cpio: path traversal %q", name)
139+
}
140+
return cleaned, nil
141+
}
142+
131143
func (r *Reader) init(rdr io.ReaderAt, size int64) error {
132144
r.r = rdr
133145
r.size = size
@@ -171,6 +183,12 @@ func (r *Reader) init(rdr io.ReaderAt, size int64) error {
171183
}
172184
offset += int64(nameSize)
173185
name := string(nameBuf[:nameSize-1]) // Remove null terminator
186+
name = strings.TrimPrefix(name, ".")
187+
cleaned, err := sanitizeArchiveName(name)
188+
if err != nil {
189+
return err
190+
}
191+
name = cleaned
174192

175193
// Check for trailer
176194
// The MKS cpio page says "TRAILER!!"
@@ -191,7 +209,7 @@ func (r *Reader) init(rdr io.ReaderAt, size int64) error {
191209
}
192210

193211
// Add to files map using inode as key
194-
r.Files[strings.TrimPrefix(name, ".")] = &File{
212+
r.Files[name] = &File{
195213
Info: FileInfo{
196214
DeviceNo: parseOctal(header.Dev[:]),
197215
Inode: parseOctal(header.Ino[:]),
@@ -202,7 +220,7 @@ func (r *Reader) init(rdr io.ReaderAt, size int64) error {
202220
RDev: int(parseOctal(header.RDev[:])),
203221
Mtime: time.Unix(int64(int64(parseOctal(header.MTime[:]))), 0),
204222
},
205-
Name: strings.TrimPrefix(name, "."),
223+
Name: name,
206224
Size: int64(fileSize),
207225
offset: offset,
208226
length: int64(fileSize),

pkg/xar/xar.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,10 @@ func (r *Reader) readXmlFileTree(xmlFile *xmlFile, dir string) (err error) {
474474
return
475475
}
476476

477-
xf.Name = path.Join(dir, xmlFile.Name)
477+
xf.Name, err = sanitizeArchiveName(path.Join(dir, xmlFile.Name))
478+
if err != nil {
479+
return err
480+
}
478481

479482
xf.Info, err = xmlFileToFileInfo(xmlFile)
480483
if err != nil {
@@ -518,6 +521,17 @@ func (r *Reader) readXmlFileTree(xmlFile *xmlFile, dir string) (err error) {
518521
return
519522
}
520523

524+
func sanitizeArchiveName(name string) (string, error) {
525+
cleaned := path.Clean(name)
526+
if cleaned == "." {
527+
return "", fmt.Errorf("xar: invalid path %q", name)
528+
}
529+
if cleaned == ".." || strings.HasPrefix(cleaned, "../") {
530+
return "", fmt.Errorf("xar: path traversal %q", name)
531+
}
532+
return cleaned, nil
533+
}
534+
521535
// Open returns a ReadCloser that provides access to the file's
522536
// uncompressed content.
523537
func (f *File) Open() (rc io.ReadCloser, err error) {

0 commit comments

Comments
 (0)