Reduce permissions changes scope after ADD/COPY
| ... | ... |
@@ -615,7 +615,7 @@ func (b *Builder) addContext(container *daemon.Container, orig, dest string, dec |
| 615 | 615 |
} |
| 616 | 616 |
|
| 617 | 617 |
if fi.IsDir() {
|
| 618 |
- return copyAsDirectory(origPath, destPath, destExists) |
|
| 618 |
+ return copyAsDirectory(origPath, destPath) |
|
| 619 | 619 |
} |
| 620 | 620 |
|
| 621 | 621 |
// If we are adding a remote file (or we've been told not to decompress), do not try to untar it |
| ... | ... |
@@ -649,37 +649,31 @@ func (b *Builder) addContext(container *daemon.Container, orig, dest string, dec |
| 649 | 649 |
resPath = path.Join(destPath, path.Base(origPath)) |
| 650 | 650 |
} |
| 651 | 651 |
|
| 652 |
- return fixPermissions(resPath, 0, 0) |
|
| 652 |
+ return fixPermissions(origPath, resPath, 0, 0) |
|
| 653 | 653 |
} |
| 654 | 654 |
|
| 655 |
-func copyAsDirectory(source, destination string, destinationExists bool) error {
|
|
| 655 |
+func copyAsDirectory(source, destination string) error {
|
|
| 656 | 656 |
if err := chrootarchive.CopyWithTar(source, destination); err != nil {
|
| 657 | 657 |
return err |
| 658 | 658 |
} |
| 659 |
- |
|
| 660 |
- if destinationExists {
|
|
| 661 |
- files, err := ioutil.ReadDir(source) |
|
| 662 |
- if err != nil {
|
|
| 663 |
- return err |
|
| 664 |
- } |
|
| 665 |
- |
|
| 666 |
- for _, file := range files {
|
|
| 667 |
- if err := fixPermissions(filepath.Join(destination, file.Name()), 0, 0); err != nil {
|
|
| 668 |
- return err |
|
| 669 |
- } |
|
| 670 |
- } |
|
| 671 |
- return nil |
|
| 672 |
- } |
|
| 673 |
- |
|
| 674 |
- return fixPermissions(destination, 0, 0) |
|
| 659 |
+ return fixPermissions(source, destination, 0, 0) |
|
| 675 | 660 |
} |
| 676 | 661 |
|
| 677 |
-func fixPermissions(destination string, uid, gid int) error {
|
|
| 678 |
- return filepath.Walk(destination, func(path string, info os.FileInfo, err error) error {
|
|
| 679 |
- if err := os.Lchown(path, uid, gid); err != nil && !os.IsNotExist(err) {
|
|
| 662 |
+func fixPermissions(source, destination string, uid, gid int) error {
|
|
| 663 |
+ // We Walk on the source rather than on the destination because we don't |
|
| 664 |
+ // want to change permissions on things we haven't created or modified. |
|
| 665 |
+ return filepath.Walk(source, func(fullpath string, info os.FileInfo, err error) error {
|
|
| 666 |
+ // Do not alter the walk root itself as it potentially existed before. |
|
| 667 |
+ if source == fullpath {
|
|
| 668 |
+ return nil |
|
| 669 |
+ } |
|
| 670 |
+ // Path is prefixed by source: substitute with destination instead. |
|
| 671 |
+ cleaned, err := filepath.Rel(source, fullpath) |
|
| 672 |
+ if err != nil {
|
|
| 680 | 673 |
return err |
| 681 | 674 |
} |
| 682 |
- return nil |
|
| 675 |
+ fullpath = path.Join(destination, cleaned) |
|
| 676 |
+ return os.Lchown(fullpath, uid, gid) |
|
| 683 | 677 |
}) |
| 684 | 678 |
} |
| 685 | 679 |
|
| ... | ... |
@@ -1066,6 +1066,31 @@ ADD . /`, |
| 1066 | 1066 |
logDone("build - add etc directory to root")
|
| 1067 | 1067 |
} |
| 1068 | 1068 |
|
| 1069 |
+// Testing #9401 |
|
| 1070 |
+func TestBuildAddPreservesFilesSpecialBits(t *testing.T) {
|
|
| 1071 |
+ name := "testaddpreservesfilesspecialbits" |
|
| 1072 |
+ defer deleteImages(name) |
|
| 1073 |
+ ctx, err := fakeContext(`FROM busybox |
|
| 1074 |
+ADD suidbin /usr/bin/suidbin |
|
| 1075 |
+RUN chmod 4755 /usr/bin/suidbin |
|
| 1076 |
+RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]
|
|
| 1077 |
+ADD ./data/ / |
|
| 1078 |
+RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]`,
|
|
| 1079 |
+ map[string]string{
|
|
| 1080 |
+ "suidbin": "suidbin", |
|
| 1081 |
+ "/data/usr/test_file": "test1", |
|
| 1082 |
+ }) |
|
| 1083 |
+ if err != nil {
|
|
| 1084 |
+ t.Fatal(err) |
|
| 1085 |
+ } |
|
| 1086 |
+ defer ctx.Close() |
|
| 1087 |
+ |
|
| 1088 |
+ if _, err := buildImageFromContext(name, ctx, true); err != nil {
|
|
| 1089 |
+ t.Fatal(err) |
|
| 1090 |
+ } |
|
| 1091 |
+ logDone("build - add preserves files special bits")
|
|
| 1092 |
+} |
|
| 1093 |
+ |
|
| 1069 | 1094 |
func TestBuildCopySingleFileToRoot(t *testing.T) {
|
| 1070 | 1095 |
name := "testcopysinglefiletoroot" |
| 1071 | 1096 |
defer deleteImages(name) |