Skip to content

Commit 6fddb5d

Browse files
Check the validity of the chmod option arguments for COPY and ADD
The current implementation silently ignores the chmod option argument for COPY and ADD if it is invalid, so this PR change to check the validity of the argument. I also found that if the value is 0o3777777777777(-1), it is ignored, and otherwise all but the lower 12 bits are meaningless. Signed-off-by: Mitsuru Kariya <[email protected]>
1 parent 3212333 commit 6fddb5d

File tree

2 files changed

+108
-3
lines changed

2 files changed

+108
-3
lines changed

frontend/dockerfile/dockerfile2llb/convert.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1363,10 +1363,11 @@ func dispatchCopy(d *dispatchState, cfg copyConfig) error {
13631363
var mode *os.FileMode
13641364
if cfg.chmod != "" {
13651365
p, err := strconv.ParseUint(cfg.chmod, 8, 32)
1366-
if err == nil {
1367-
perm := os.FileMode(p)
1368-
mode = &perm
1366+
if err != nil || p > 0o7777 {
1367+
return errors.Errorf("invalid chmod parameter: '%v'. it should be octal string and between 0 and 07777", cfg.chmod)
13691368
}
1369+
perm := os.FileMode(p)
1370+
mode = &perm
13701371
}
13711372

13721373
if cfg.checksum != "" {

frontend/dockerfile/dockerfile_test.go

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,13 @@ var allTests = integration.TestFuncs(
161161
testCopySymlinks,
162162
testCopyChown,
163163
testCopyChmod,
164+
testCopyInvalidChmod,
164165
testCopyOverrideFiles,
165166
testCopyVarSubstitution,
166167
testCopyWildcards,
167168
testCopyRelative,
168169
testAddURLChmod,
170+
testAddInvalidChmod,
169171
testTarContext,
170172
testTarContextExternalDockerfile,
171173
testWorkdirUser,
@@ -3516,6 +3518,57 @@ COPY --from=base /out /
35163518
require.Equal(t, "0000\n", string(dt))
35173519
}
35183520

3521+
func testCopyInvalidChmod(t *testing.T, sb integration.Sandbox) {
3522+
integration.SkipOnPlatform(t, "windows")
3523+
f := getFrontend(t, sb)
3524+
3525+
dockerfile := []byte(`
3526+
FROM scratch
3527+
COPY --chmod=64a foo /
3528+
`)
3529+
3530+
dir := integration.Tmpdir(
3531+
t,
3532+
fstest.CreateFile("Dockerfile", dockerfile, 0600),
3533+
fstest.CreateFile("foo", []byte(`foo-contents`), 0600),
3534+
)
3535+
3536+
c, err := client.New(sb.Context(), sb.Address())
3537+
require.NoError(t, err)
3538+
defer c.Close()
3539+
3540+
_, err = f.Solve(sb.Context(), c, client.SolveOpt{
3541+
LocalMounts: map[string]fsutil.FS{
3542+
dockerui.DefaultLocalNameDockerfile: dir,
3543+
dockerui.DefaultLocalNameContext: dir,
3544+
},
3545+
}, nil)
3546+
require.ErrorContains(t, err, "invalid chmod parameter: '64a'. it should be octal string and between 0 and 07777")
3547+
3548+
dockerfile = []byte(`
3549+
FROM scratch
3550+
COPY --chmod=10000 foo /
3551+
`)
3552+
3553+
dir = integration.Tmpdir(
3554+
t,
3555+
fstest.CreateFile("Dockerfile", dockerfile, 0600),
3556+
fstest.CreateFile("foo", []byte(`foo-contents`), 0600),
3557+
)
3558+
3559+
c, err = client.New(sb.Context(), sb.Address())
3560+
require.NoError(t, err)
3561+
defer c.Close()
3562+
3563+
_, err = f.Solve(sb.Context(), c, client.SolveOpt{
3564+
LocalMounts: map[string]fsutil.FS{
3565+
dockerui.DefaultLocalNameDockerfile: dir,
3566+
dockerui.DefaultLocalNameContext: dir,
3567+
},
3568+
}, nil)
3569+
require.ErrorContains(t, err, "invalid chmod parameter: '10000'. it should be octal string and between 0 and 07777")
3570+
}
3571+
35193572
func testCopyOverrideFiles(t *testing.T, sb integration.Sandbox) {
35203573
integration.SkipOnPlatform(t, "windows")
35213574
f := getFrontend(t, sb)
@@ -3803,6 +3856,57 @@ COPY --from=build /dest /dest
38033856
require.Equal(t, []byte("0644\n0755\n0413\n"), dt)
38043857
}
38053858

3859+
func testAddInvalidChmod(t *testing.T, sb integration.Sandbox) {
3860+
integration.SkipOnPlatform(t, "windows")
3861+
f := getFrontend(t, sb)
3862+
3863+
dockerfile := []byte(`
3864+
FROM scratch
3865+
ADD --chmod=64a foo /
3866+
`)
3867+
3868+
dir := integration.Tmpdir(
3869+
t,
3870+
fstest.CreateFile("Dockerfile", dockerfile, 0600),
3871+
fstest.CreateFile("foo", []byte(`foo-contents`), 0600),
3872+
)
3873+
3874+
c, err := client.New(sb.Context(), sb.Address())
3875+
require.NoError(t, err)
3876+
defer c.Close()
3877+
3878+
_, err = f.Solve(sb.Context(), c, client.SolveOpt{
3879+
LocalMounts: map[string]fsutil.FS{
3880+
dockerui.DefaultLocalNameDockerfile: dir,
3881+
dockerui.DefaultLocalNameContext: dir,
3882+
},
3883+
}, nil)
3884+
require.ErrorContains(t, err, "invalid chmod parameter: '64a'. it should be octal string and between 0 and 07777")
3885+
3886+
dockerfile = []byte(`
3887+
FROM scratch
3888+
ADD --chmod=10000 foo /
3889+
`)
3890+
3891+
dir = integration.Tmpdir(
3892+
t,
3893+
fstest.CreateFile("Dockerfile", dockerfile, 0600),
3894+
fstest.CreateFile("foo", []byte(`foo-contents`), 0600),
3895+
)
3896+
3897+
c, err = client.New(sb.Context(), sb.Address())
3898+
require.NoError(t, err)
3899+
defer c.Close()
3900+
3901+
_, err = f.Solve(sb.Context(), c, client.SolveOpt{
3902+
LocalMounts: map[string]fsutil.FS{
3903+
dockerui.DefaultLocalNameDockerfile: dir,
3904+
dockerui.DefaultLocalNameContext: dir,
3905+
},
3906+
}, nil)
3907+
require.ErrorContains(t, err, "invalid chmod parameter: '10000'. it should be octal string and between 0 and 07777")
3908+
}
3909+
38063910
func testDockerfileFromGit(t *testing.T, sb integration.Sandbox) {
38073911
integration.SkipOnPlatform(t, "windows")
38083912
f := getFrontend(t, sb)

0 commit comments

Comments
 (0)