@@ -47,11 +47,12 @@ const (
47
47
)
48
48
49
49
var (
50
- errBadMntOption = errors .New ("invalid mount option" )
51
- errBadOptionArg = errors .New ("must provide an argument for option" )
52
- errBadVolDest = errors .New ("must set volume destination" )
53
- errBadVolSrc = errors .New ("must set volume source" )
54
- errDuplicateDest = errors .New ("duplicate mount destination" )
50
+ errBadMntOption = errors .New ("invalid mount option" )
51
+ errBadOptionArg = errors .New ("must provide an argument for option" )
52
+ errBadOptionNoArg = errors .New ("must not provide an argument for option" )
53
+ errBadVolDest = errors .New ("must set volume destination" )
54
+ errBadVolSrc = errors .New ("must set volume source" )
55
+ errDuplicateDest = errors .New ("duplicate mount destination" )
55
56
)
56
57
57
58
// CacheParent returns a cache parent for --mount=type=cache
@@ -144,33 +145,43 @@ func GetBindMount(sys *types.SystemContext, args []string, contextDir string, st
144
145
argName , argValue , hasArgValue := strings .Cut (val , "=" )
145
146
switch argName {
146
147
case "type" :
147
- // This is already processed
148
+ // This is already processed, and should be "bind"
148
149
continue
149
150
case "bind-nonrecursive" :
151
+ if hasArgValue {
152
+ return newMount , "" , "" , "" , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
153
+ }
150
154
newMount .Options = append (newMount .Options , "bind" )
151
155
bindNonRecursive = true
152
156
case "nosuid" , "nodev" , "noexec" :
153
- // TODO: detect duplication of these options.
154
- // (Is this necessary?)
157
+ if hasArgValue {
158
+ return newMount , "" , "" , "" , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
159
+ }
155
160
newMount .Options = append (newMount .Options , argName )
156
161
case "rw" , "readwrite" :
162
+ if hasArgValue {
163
+ return newMount , "" , "" , "" , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
164
+ }
157
165
newMount .Options = append (newMount .Options , "rw" )
158
166
mountReadability = "rw"
159
167
case "ro" , "readonly" :
168
+ if hasArgValue {
169
+ return newMount , "" , "" , "" , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
170
+ }
160
171
newMount .Options = append (newMount .Options , "ro" )
161
172
mountReadability = "ro"
162
173
case "shared" , "rshared" , "private" , "rprivate" , "slave" , "rslave" , "Z" , "z" , "U" , "no-dereference" :
163
174
if hasArgValue {
164
- return newMount , "" , "" , "" , fmt .Errorf ("%v: %w" , val , errBadOptionArg )
175
+ return newMount , "" , "" , "" , fmt .Errorf ("%v: %w" , val , errBadOptionNoArg )
165
176
}
166
177
newMount .Options = append (newMount .Options , argName )
167
178
case "from" :
168
- if ! hasArgValue {
179
+ if ! hasArgValue || argValue == "" {
169
180
return newMount , "" , "" , "" , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
170
181
}
171
182
fromImage = argValue
172
183
case "bind-propagation" :
173
- if ! hasArgValue {
184
+ if ! hasArgValue || argValue == "" {
174
185
return newMount , "" , "" , "" , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
175
186
}
176
187
switch argValue {
@@ -181,12 +192,12 @@ func GetBindMount(sys *types.SystemContext, args []string, contextDir string, st
181
192
}
182
193
newMount .Options = append (newMount .Options , argValue )
183
194
case "src" , "source" :
184
- if ! hasArgValue {
195
+ if ! hasArgValue || argValue == "" {
185
196
return newMount , "" , "" , "" , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
186
197
}
187
198
newMount .Source = argValue
188
199
case "target" , "dst" , "destination" :
189
- if ! hasArgValue {
200
+ if ! hasArgValue || argValue == "" {
190
201
return newMount , "" , "" , "" , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
191
202
}
192
203
targetPath := argValue
@@ -199,6 +210,9 @@ func GetBindMount(sys *types.SystemContext, args []string, contextDir string, st
199
210
}
200
211
newMount .Destination = targetPath
201
212
case "relabel" :
213
+ if ! hasArgValue || argValue == "" {
214
+ return newMount , "" , "" , "" , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
215
+ }
202
216
if setRelabel != "" {
203
217
return newMount , "" , "" , "" , fmt .Errorf ("cannot pass 'relabel' option more than once: %w" , errBadOptionArg )
204
218
}
@@ -248,6 +262,7 @@ func GetBindMount(sys *types.SystemContext, args []string, contextDir string, st
248
262
return newMount , "" , "" , "" , err
249
263
}
250
264
mountedImage = image .ID ()
265
+ // unmount the image if we don't end up returning successfully
251
266
defer func () {
252
267
if ! succeeded {
253
268
if _ , err := store .UnmountImage (mountedImage , false ); err != nil {
@@ -335,12 +350,10 @@ func GetCacheMount(args []string, additionalMountPoints map[string]internal.Stag
335
350
var err error
336
351
var mode uint64
337
352
var buildahLockFilesDir string
338
- var (
339
- setDest bool
340
- setShared bool
341
- setReadOnly bool
342
- foundSElinuxLabel bool
343
- )
353
+ var setShared bool
354
+ setDest := ""
355
+ setRelabel := ""
356
+ setReadOnly := ""
344
357
fromStage := ""
345
358
newMount := specs.Mount {
346
359
Type : define .TypeBind ,
@@ -360,28 +373,44 @@ func GetCacheMount(args []string, additionalMountPoints map[string]internal.Stag
360
373
argName , argValue , hasArgValue := strings .Cut (val , "=" )
361
374
switch argName {
362
375
case "type" :
363
- // This is already processed
376
+ // This is already processed, and should be "cache"
364
377
continue
365
- case "nosuid" , "nodev" , "noexec" :
366
- // TODO: detect duplication of these options.
367
- // (Is this necessary?)
378
+ case "nosuid" , "nodev" , "noexec" , "U" :
379
+ if hasArgValue {
380
+ return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
381
+ }
368
382
newMount .Options = append (newMount .Options , argName )
369
383
case "rw" , "readwrite" :
384
+ if hasArgValue {
385
+ return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
386
+ }
370
387
newMount .Options = append (newMount .Options , "rw" )
388
+ setReadOnly = "rw"
371
389
case "readonly" , "ro" :
372
- // Alias for "ro"
390
+ if hasArgValue {
391
+ return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
392
+ }
373
393
newMount .Options = append (newMount .Options , "ro" )
374
- setReadOnly = true
394
+ setReadOnly = "ro"
375
395
case "Z" , "z" :
396
+ if hasArgValue {
397
+ return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
398
+ }
376
399
newMount .Options = append (newMount .Options , argName )
377
- foundSElinuxLabel = true
378
- case "shared" , "rshared" , "private" , "rprivate" , "slave" , "rslave" , "U" :
400
+ setRelabel = argName
401
+ case "shared" , "rshared" , "private" , "rprivate" , "slave" , "rslave" :
402
+ if hasArgValue {
403
+ return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
404
+ }
379
405
newMount .Options = append (newMount .Options , argName )
380
406
setShared = true
381
407
case "sharing" :
408
+ if ! hasArgValue || argValue == "" {
409
+ return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
410
+ }
382
411
sharing = argValue
383
412
case "bind-propagation" :
384
- if ! hasArgValue {
413
+ if ! hasArgValue || argValue == "" {
385
414
return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
386
415
}
387
416
switch argValue {
@@ -392,17 +421,17 @@ func GetCacheMount(args []string, additionalMountPoints map[string]internal.Stag
392
421
}
393
422
newMount .Options = append (newMount .Options , argValue )
394
423
case "id" :
395
- if ! hasArgValue {
424
+ if ! hasArgValue || argValue == "" {
396
425
return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
397
426
}
398
427
id = argValue
399
428
case "from" :
400
- if ! hasArgValue {
429
+ if ! hasArgValue || argValue == "" {
401
430
return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
402
431
}
403
432
fromStage = argValue
404
433
case "target" , "dst" , "destination" :
405
- if ! hasArgValue {
434
+ if ! hasArgValue || argValue == "" {
406
435
return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
407
436
}
408
437
targetPath := argValue
@@ -413,30 +442,30 @@ func GetCacheMount(args []string, additionalMountPoints map[string]internal.Stag
413
442
return newMount , "" , nil , err
414
443
}
415
444
newMount .Destination = targetPath
416
- setDest = true
445
+ setDest = targetPath
417
446
case "src" , "source" :
418
- if ! hasArgValue {
447
+ if ! hasArgValue || argValue == "" {
419
448
return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
420
449
}
421
450
newMount .Source = argValue
422
451
case "mode" :
423
- if ! hasArgValue {
452
+ if ! hasArgValue || argValue == "" {
424
453
return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
425
454
}
426
455
mode , err = strconv .ParseUint (argValue , 8 , 32 )
427
456
if err != nil {
428
457
return newMount , "" , nil , fmt .Errorf ("unable to parse cache mode: %w" , err )
429
458
}
430
459
case "uid" :
431
- if ! hasArgValue {
460
+ if ! hasArgValue || argValue == "" {
432
461
return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
433
462
}
434
463
uid , err = strconv .Atoi (argValue )
435
464
if err != nil {
436
465
return newMount , "" , nil , fmt .Errorf ("unable to parse cache uid: %w" , err )
437
466
}
438
467
case "gid" :
439
- if ! hasArgValue {
468
+ if ! hasArgValue || argValue == "" {
440
469
return newMount , "" , nil , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
441
470
}
442
471
gid , err = strconv .Atoi (argValue )
@@ -450,11 +479,11 @@ func GetCacheMount(args []string, additionalMountPoints map[string]internal.Stag
450
479
451
480
// If selinux is enabled and no selinux option was configured
452
481
// default to `z` i.e shared content label.
453
- if ! foundSElinuxLabel && (selinux .EnforceMode () != selinux .Disabled ) && fromStage == "" {
482
+ if setRelabel == "" && (selinux .EnforceMode () != selinux .Disabled ) && fromStage == "" {
454
483
newMount .Options = append (newMount .Options , "z" )
455
484
}
456
485
457
- if ! setDest {
486
+ if setDest == "" {
458
487
return newMount , "" , nil , errBadVolDest
459
488
}
460
489
@@ -478,7 +507,7 @@ func GetCacheMount(args []string, additionalMountPoints map[string]internal.Stag
478
507
}
479
508
thisCacheRoot = mountPoint
480
509
} else {
481
- // we need to create the cache directory on the host if no image is being used
510
+ // we need to create the cache directory on the host if no stage is being used
482
511
483
512
// since type is cache and a cache can be reused by consecutive builds
484
513
// create a common cache directory, which persists on hosts within temp lifecycle
@@ -561,8 +590,8 @@ func GetCacheMount(args []string, additionalMountPoints map[string]internal.Stag
561
590
newMount .Options = append (newMount .Options , "shared" )
562
591
}
563
592
564
- // buildkit parity: cache must writable unless `ro` or `readonly` is configured explicitly
565
- if ! setReadOnly {
593
+ // buildkit parity: cache must be writable unless `ro` or `readonly` is configured explicitly
594
+ if setReadOnly == "" {
566
595
newMount .Options = append (newMount .Options , "rw" )
567
596
}
568
597
@@ -727,9 +756,6 @@ func getMounts(ctx *types.SystemContext, store storage.Store, mountLabel string,
727
756
728
757
errInvalidSyntax := errors .New ("incorrect mount format: should be --mount type=<bind|tmpfs>,[src=<host-dir>,]target=<ctr-dir>[,options]" )
729
758
730
- // TODO(vrothberg): the manual parsing can be replaced with a regular expression
731
- // to allow a more robust parsing of the mount format and to give
732
- // precise errors regarding supported format versus supported options.
733
759
for _ , mount := range mounts {
734
760
tokens := strings .Split (mount , "," )
735
761
if len (tokens ) < 2 {
@@ -809,30 +835,36 @@ func GetTmpfsMount(args []string, workDir string) (specs.Mount, error) {
809
835
argName , argValue , hasArgValue := strings .Cut (val , "=" )
810
836
switch argName {
811
837
case "type" :
812
- // This is already processed
838
+ // This is already processed, and should be "tmpfs"
813
839
continue
814
- case "ro" , "nosuid" , "nodev" , "noexec" :
840
+ case "nosuid" , "nodev" , "noexec" :
841
+ if hasArgValue {
842
+ return newMount , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
843
+ }
815
844
newMount .Options = append (newMount .Options , argName )
816
- case "readonly" :
817
- // Alias for "ro"
845
+ case "ro" , "readonly" :
846
+ if hasArgValue {
847
+ return newMount , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
848
+ }
818
849
newMount .Options = append (newMount .Options , "ro" )
819
850
case "tmpcopyup" :
851
+ if hasArgValue {
852
+ return newMount , fmt .Errorf ("%v: %w" , argName , errBadOptionNoArg )
853
+ }
820
854
// the path that is shadowed by the tmpfs mount is recursively copied up to the tmpfs itself.
821
855
newMount .Options = append (newMount .Options , argName )
822
856
case "tmpfs-mode" :
823
- if ! hasArgValue {
857
+ if ! hasArgValue || argValue == "" {
824
858
return newMount , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
825
859
}
826
860
newMount .Options = append (newMount .Options , fmt .Sprintf ("mode=%s" , argValue ))
827
861
case "tmpfs-size" :
828
- if ! hasArgValue {
862
+ if ! hasArgValue || argValue == "" {
829
863
return newMount , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
830
864
}
831
865
newMount .Options = append (newMount .Options , fmt .Sprintf ("size=%s" , argValue ))
832
- case "src" , "source" :
833
- return newMount , errors .New ("source is not supported with tmpfs mounts" )
834
866
case "target" , "dst" , "destination" :
835
- if ! hasArgValue {
867
+ if ! hasArgValue || argValue == "" {
836
868
return newMount , fmt .Errorf ("%v: %w" , argName , errBadOptionArg )
837
869
}
838
870
targetPath := argValue
0 commit comments