Skip to content

Commit d26587c

Browse files
committed
archive: disable looking up usernames and groupnames on the host
These strings were resolved using the user information on the host filesystem and were decreasing reproducibility. For moby/buildkit issue 3688 Signed-off-by: Akihiro Suda <[email protected]>
1 parent 744809b commit d26587c

4 files changed

Lines changed: 147 additions & 1 deletion

File tree

.golangci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ issues:
2929
text: "blank-imports:"
3030
- path: 'contrib[\\/]fuzz[\\/]'
3131
text: "exported: func name will be used as fuzz.Fuzz"
32+
- path: 'archive[\\/]tarheader[\\/]'
33+
# conversion is necessary on Linux, unnecessary on macOS
34+
text: "unnecessary conversion"
3235

3336
linters-settings:
3437
gosec:

archive/tar.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import (
2929
"syscall"
3030
"time"
3131

32+
"github.com/containerd/containerd/archive/tarheader"
3233
"github.com/containerd/containerd/log"
3334
"github.com/containerd/containerd/pkg/epoch"
3435
"github.com/containerd/containerd/pkg/userns"
@@ -586,7 +587,8 @@ func (cw *ChangeWriter) HandleChange(k fs.ChangeKind, p string, f os.FileInfo, e
586587
}
587588
}
588589

589-
hdr, err := tar.FileInfoHeader(f, link)
590+
// Use FileInfoHeaderNoLookups to avoid propagating user names and group names from the host
591+
hdr, err := tarheader.FileInfoHeaderNoLookups(f, link)
590592
if err != nil {
591593
return err
592594
}

archive/tarheader/tarheader.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
Copyright The containerd Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
/*
18+
Portions from https://github.com/moby/moby/blob/v23.0.1/pkg/archive/archive.go#L419-L464
19+
Copyright (C) Docker/Moby authors.
20+
Licensed under the Apache License, Version 2.0
21+
NOTICE: https://github.com/moby/moby/blob/v23.0.1/NOTICE
22+
*/
23+
24+
package tarheader
25+
26+
import (
27+
"archive/tar"
28+
"os"
29+
)
30+
31+
// nosysFileInfo hides the system-dependent info of the wrapped FileInfo to
32+
// prevent tar.FileInfoHeader from introspecting it and potentially calling into
33+
// glibc.
34+
//
35+
// From https://github.com/moby/moby/blob/v23.0.1/pkg/archive/archive.go#L419-L434 .
36+
type nosysFileInfo struct {
37+
os.FileInfo
38+
}
39+
40+
func (fi nosysFileInfo) Sys() interface{} {
41+
// A Sys value of type *tar.Header is safe as it is system-independent.
42+
// The tar.FileInfoHeader function copies the fields into the returned
43+
// header without performing any OS lookups.
44+
if sys, ok := fi.FileInfo.Sys().(*tar.Header); ok {
45+
return sys
46+
}
47+
return nil
48+
}
49+
50+
// sysStat, if non-nil, populates hdr from system-dependent fields of fi.
51+
//
52+
// From https://github.com/moby/moby/blob/v23.0.1/pkg/archive/archive.go#L436-L437 .
53+
var sysStat func(fi os.FileInfo, hdr *tar.Header) error
54+
55+
// FileInfoHeaderNoLookups creates a partially-populated tar.Header from fi.
56+
//
57+
// Compared to the archive/tar.FileInfoHeader function, this function is safe to
58+
// call from a chrooted process as it does not populate fields which would
59+
// require operating system lookups. It behaves identically to
60+
// tar.FileInfoHeader when fi is a FileInfo value returned from
61+
// tar.Header.FileInfo().
62+
//
63+
// When fi is a FileInfo for a native file, such as returned from os.Stat() and
64+
// os.Lstat(), the returned Header value differs from one returned from
65+
// tar.FileInfoHeader in the following ways. The Uname and Gname fields are not
66+
// set as OS lookups would be required to populate them. The AccessTime and
67+
// ChangeTime fields are not currently set (not yet implemented) although that
68+
// is subject to change. Callers which require the AccessTime or ChangeTime
69+
// fields to be zeroed should explicitly zero them out in the returned Header
70+
// value to avoid any compatibility issues in the future.
71+
//
72+
// From https://github.com/moby/moby/blob/v23.0.1/pkg/archive/archive.go#L439-L464 .
73+
func FileInfoHeaderNoLookups(fi os.FileInfo, link string) (*tar.Header, error) {
74+
hdr, err := tar.FileInfoHeader(nosysFileInfo{fi}, link)
75+
if err != nil {
76+
return nil, err
77+
}
78+
if sysStat != nil {
79+
return hdr, sysStat(fi, hdr)
80+
}
81+
return hdr, nil
82+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//go:build !windows
2+
3+
/*
4+
Copyright The containerd Authors.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
/*
20+
Portions from https://github.com/moby/moby/blob/v23.0.1/pkg/archive/archive_unix.go#L52-L70
21+
Copyright (C) Docker/Moby authors.
22+
Licensed under the Apache License, Version 2.0
23+
NOTICE: https://github.com/moby/moby/blob/v23.0.1/NOTICE
24+
*/
25+
26+
package tarheader
27+
28+
import (
29+
"archive/tar"
30+
"os"
31+
"syscall"
32+
33+
"golang.org/x/sys/unix"
34+
)
35+
36+
func init() {
37+
sysStat = statUnix
38+
}
39+
40+
// statUnix populates hdr from system-dependent fields of fi without performing
41+
// any OS lookups.
42+
// From https://github.com/moby/moby/blob/v23.0.1/pkg/archive/archive_unix.go#L52-L70
43+
func statUnix(fi os.FileInfo, hdr *tar.Header) error {
44+
s, ok := fi.Sys().(*syscall.Stat_t)
45+
if !ok {
46+
return nil
47+
}
48+
49+
hdr.Uid = int(s.Uid)
50+
hdr.Gid = int(s.Gid)
51+
52+
if s.Mode&unix.S_IFBLK != 0 ||
53+
s.Mode&unix.S_IFCHR != 0 {
54+
hdr.Devmajor = int64(unix.Major(uint64(s.Rdev)))
55+
hdr.Devminor = int64(unix.Minor(uint64(s.Rdev)))
56+
}
57+
58+
return nil
59+
}

0 commit comments

Comments
 (0)