Skip to content

Commit 7ad08c6

Browse files
authored
Merge pull request from GHSA-c72p-9xmj-rx3w
[release/1.5] Use chmod path for checking symlink
2 parents 0e8719f + f5c7cb6 commit 7ad08c6

File tree

6 files changed

+71
-21
lines changed

6 files changed

+71
-21
lines changed

archive/tar.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,9 +393,8 @@ func createTarFile(ctx context.Context, path, extractDir string, hdr *tar.Header
393393
}
394394
}
395395

396-
// There is no LChmod, so ignore mode for symlink. Also, this
397-
// must happen after chown, as that can modify the file mode
398-
if err := handleLChmod(hdr, path, hdrInfo); err != nil {
396+
// call lchmod after lchown since lchown can modify the file mode
397+
if err := lchmod(path, hdrInfo.Mode()); err != nil {
399398
return err
400399
}
401400

archive/tar_freebsd.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818

1919
package archive
2020

21-
import "golang.org/x/sys/unix"
21+
import (
22+
"os"
23+
24+
"golang.org/x/sys/unix"
25+
)
2226

2327
// mknod wraps unix.Mknod. FreeBSD's unix.Mknod signature is different from
2428
// other Unix and Unix-like operating systems.
@@ -34,3 +38,11 @@ func lsetxattrCreate(link string, attr string, data []byte) error {
3438
}
3539
return err
3640
}
41+
42+
func lchmod(path string, mode os.FileMode) error {
43+
err := unix.Fchmodat(unix.AT_FDCWD, path, uint32(mode), unix.AT_SYMLINK_NOFOLLOW)
44+
if err != nil {
45+
err = &os.PathError{Op: "lchmod", Path: path, Err: err}
46+
}
47+
return err
48+
}

archive/tar_mostunix.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@
1818

1919
package archive
2020

21-
import "golang.org/x/sys/unix"
21+
import (
22+
"os"
23+
24+
"golang.org/x/sys/unix"
25+
)
2226

2327
// mknod wraps Unix.Mknod and casts dev to int
2428
func mknod(path string, mode uint32, dev uint64) error {
@@ -34,3 +38,18 @@ func lsetxattrCreate(link string, attr string, data []byte) error {
3438
}
3539
return err
3640
}
41+
42+
// lchmod checks for symlink and changes the mode if not a symlink
43+
func lchmod(path string, mode os.FileMode) error {
44+
fi, err := os.Lstat(path)
45+
if err != nil {
46+
return err
47+
}
48+
49+
if fi.Mode()&os.ModeSymlink == 0 {
50+
if err := os.Chmod(path, mode); err != nil {
51+
return err
52+
}
53+
}
54+
return nil
55+
}

archive/tar_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,11 @@ func TestBreakouts(t *testing.T) {
243243
return nil
244244
}
245245
errFileDiff := errors.New("files differ")
246+
td, err := ioutil.TempDir("", "test-breakouts-")
247+
if err != nil {
248+
t.Fatal(err)
249+
}
250+
defer os.RemoveAll(td)
246251

247252
isSymlinkFile := func(f string) func(string) error {
248253
return func(root string) error {
@@ -744,6 +749,36 @@ func TestBreakouts(t *testing.T) {
744749
// resolution ends up just removing etc
745750
validator: fileNotExists("etc/passwd"),
746751
},
752+
{
753+
754+
name: "HardlinkSymlinkChmod",
755+
w: func() tartest.WriterToTar {
756+
p := filepath.Join(td, "perm400")
757+
if err := ioutil.WriteFile(p, []byte("..."), 0400); err != nil {
758+
t.Fatal(err)
759+
}
760+
ep := filepath.Join(td, "also-exists-outside-root")
761+
if err := ioutil.WriteFile(ep, []byte("..."), 0640); err != nil {
762+
t.Fatal(err)
763+
}
764+
765+
return tartest.TarAll(
766+
tc.Symlink(p, ep),
767+
tc.Link(ep, "sketchylink"),
768+
)
769+
}(),
770+
validator: func(string) error {
771+
p := filepath.Join(td, "perm400")
772+
fi, err := os.Lstat(p)
773+
if err != nil {
774+
return err
775+
}
776+
if perm := fi.Mode() & os.ModePerm; perm != 0400 {
777+
return errors.Errorf("%s perm changed from 0400 to %04o", p, perm)
778+
}
779+
return nil
780+
},
781+
},
747782
}
748783

749784
for _, bo := range breakouts {

archive/tar_unix.go

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -111,21 +111,6 @@ func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
111111
return mknod(path, mode, unix.Mkdev(uint32(hdr.Devmajor), uint32(hdr.Devminor)))
112112
}
113113

114-
func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
115-
if hdr.Typeflag == tar.TypeLink {
116-
if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
117-
if err := os.Chmod(path, hdrInfo.Mode()); err != nil && !os.IsNotExist(err) {
118-
return err
119-
}
120-
}
121-
} else if hdr.Typeflag != tar.TypeSymlink {
122-
if err := os.Chmod(path, hdrInfo.Mode()); err != nil {
123-
return err
124-
}
125-
}
126-
return nil
127-
}
128-
129114
func getxattr(path, attr string) ([]byte, error) {
130115
b, err := sysx.LGetxattr(path, attr)
131116
if err == unix.ENOTSUP || err == sysx.ENODATA {

archive/tar_windows.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {
9898
return nil
9999
}
100100

101-
func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
101+
func lchmod(path string, mode os.FileMode) error {
102102
return nil
103103
}
104104

0 commit comments

Comments
 (0)