Skip to content

Commit bc1bdb8

Browse files
Prohibit using a differential disk as a base disk
Co-authored-by: Jan Dubois <[email protected]> Signed-off-by: Akihiro Suda <[email protected]>
1 parent bfa5bab commit bc1bdb8

File tree

4 files changed

+71
-33
lines changed

4 files changed

+71
-33
lines changed

pkg/qemu/imgutil/imgutil.go

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import (
55
"encoding/json"
66
"fmt"
77
"os/exec"
8-
"path/filepath"
9-
"strings"
8+
9+
"github.com/sirupsen/logrus"
1010
)
1111

1212
type InfoChild struct {
@@ -111,19 +111,42 @@ func GetInfo(f string) (*Info, error) {
111111
return ParseInfo(stdout.Bytes())
112112
}
113113

114-
func DetectFormat(f string) (string, error) {
115-
switch ext := strings.ToLower(filepath.Ext(f)); ext {
116-
case ".qcow2":
117-
return "qcow2", nil
118-
case ".raw":
119-
return "raw", nil
114+
func AcceptableAsBasedisk(info *Info) error {
115+
switch info.Format {
116+
case "qcow2", "raw":
117+
// NOP
118+
default:
119+
logrus.WithField("filename", info.Filename).
120+
Warnf("Unsupported image format %q. The image may not boot, or may have an extra privilege to access the host filesystem. Use with caution.", info.Format)
121+
}
122+
if info.BackingFilename != "" {
123+
return fmt.Errorf("base disk (%q) must not have a backing file (%q)", info.Filename, info.BackingFilename)
120124
}
121-
imgInfo, err := GetInfo(f)
122-
if err != nil {
123-
return "", err
125+
if info.FullBackingFilename != "" {
126+
return fmt.Errorf("base disk (%q) must not have a backing file (%q)", info.Filename, info.FullBackingFilename)
124127
}
125-
if imgInfo.Format == "" {
126-
return "", fmt.Errorf("failed to detect format of %q", f)
128+
if info.FormatSpecific != nil {
129+
if vmdk := info.FormatSpecific.Vmdk(); vmdk != nil {
130+
for _, e := range vmdk.Extents {
131+
if e.Filename != info.Filename {
132+
return fmt.Errorf("base disk (%q) must not have an extent file (%q)", info.Filename, e.Filename)
133+
}
134+
}
135+
}
127136
}
128-
return imgInfo.Format, nil
137+
// info.Children is set since QEMU 8.0
138+
switch len(info.Children) {
139+
case 0:
140+
// NOP
141+
case 1:
142+
if info.Filename != info.Children[0].Info.Filename {
143+
return fmt.Errorf("base disk (%q) child must not have a different filename (%q)", info.Filename, info.Children[0].Info.Filename)
144+
}
145+
if len(info.Children[0].Info.Children) > 0 {
146+
return fmt.Errorf("base disk (%q) child must not have children of its own", info.Filename)
147+
}
148+
default:
149+
return fmt.Errorf("base disk (%q) must not have multiple children: %+v", info.Filename, info.Children)
150+
}
151+
return nil
129152
}

pkg/qemu/qemu.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,19 @@ func EnsureDisk(cfg Config) error {
9696
if err != nil {
9797
return err
9898
}
99+
baseDiskInfo, err := imgutil.GetInfo(baseDisk)
100+
if err != nil {
101+
return fmt.Errorf("failed to get the information of base disk %q: %w", baseDisk, err)
102+
}
103+
if err = imgutil.AcceptableAsBasedisk(baseDiskInfo); err != nil {
104+
return fmt.Errorf("file %q is not acceptable as the base disk: %w", baseDisk, err)
105+
}
106+
if baseDiskInfo.Format == "" {
107+
return fmt.Errorf("failed to inspect the format of %q", baseDisk)
108+
}
99109
args := []string{"create", "-f", "qcow2"}
100110
if !isBaseDiskISO {
101-
baseDiskFormat, err := imgutil.DetectFormat(baseDisk)
102-
if err != nil {
103-
return err
104-
}
105-
args = append(args, "-F", baseDiskFormat, "-b", baseDisk)
111+
args = append(args, "-F", baseDiskInfo.Format, "-b", baseDisk)
106112
}
107113
args = append(args, diffDisk, strconv.Itoa(int(diskSize)))
108114
cmd := exec.Command("qemu-img", args...)
@@ -581,6 +587,9 @@ func Cmdline(cfg Config) (string, []string, error) {
581587
if err != nil {
582588
return "", nil, fmt.Errorf("failed to get the information of %q: %w", baseDisk, err)
583589
}
590+
if err = imgutil.AcceptableAsBasedisk(baseDiskInfo); err != nil {
591+
return "", nil, fmt.Errorf("file %q is not acceptable as the base disk: %w", baseDisk, err)
592+
}
584593
if baseDiskInfo.Format == "" {
585594
return "", nil, fmt.Errorf("failed to inspect the format of %q", baseDisk)
586595
}

pkg/vz/disk.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,13 +49,19 @@ func EnsureDisk(driver *driver.BaseDriver) error {
4949
if err != nil {
5050
return err
5151
}
52+
baseDiskInfo, err := imgutil.GetInfo(baseDisk)
53+
if err != nil {
54+
return fmt.Errorf("failed to get the information of base disk %q: %w", baseDisk, err)
55+
}
56+
if err = imgutil.AcceptableAsBasedisk(baseDiskInfo); err != nil {
57+
return fmt.Errorf("file %q is not acceptable as the base disk: %w", baseDisk, err)
58+
}
59+
if baseDiskInfo.Format == "" {
60+
return fmt.Errorf("failed to inspect the format of %q", baseDisk)
61+
}
5262
args := []string{"create", "-f", "qcow2"}
5363
if !isBaseDiskISO {
54-
baseDiskFormat, err := imgutil.DetectFormat(baseDisk)
55-
if err != nil {
56-
return err
57-
}
58-
args = append(args, "-F", baseDiskFormat, "-b", baseDisk)
64+
args = append(args, "-F", baseDiskInfo.Format, "-b", baseDisk)
5965
}
6066
args = append(args, diffDisk, strconv.Itoa(int(diskSize)))
6167
cmd := exec.Command("qemu-img", args...)

pkg/vz/vm_darwin.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -373,12 +373,12 @@ func attachNetwork(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfigu
373373
}
374374

375375
func validateDiskFormat(diskPath string) error {
376-
format, err := imgutil.DetectFormat(diskPath)
376+
info, err := imgutil.GetInfo(diskPath)
377377
if err != nil {
378378
return fmt.Errorf("failed to detect the format of %q: %w", diskPath, err)
379379
}
380-
if format != "raw" {
381-
return fmt.Errorf("expected the format of %q to be \"raw\", got %q", diskPath, format)
380+
if info.Format != "raw" {
381+
return fmt.Errorf("expected the format of %q to be \"raw\", got %q", diskPath, info.Format)
382382
}
383383
// TODO: ensure that the disk is formatted with GPT or ISO9660
384384
return nil
@@ -437,23 +437,23 @@ func attachDisks(driver *driver.BaseDriver, vmConfig *vz.VirtualMachineConfigura
437437
}
438438
extraDiskPath := filepath.Join(d.Dir, filenames.DataDisk)
439439

440-
extraDiskFormat, err := imgutil.DetectFormat(extraDiskPath)
440+
extraDiskInfo, err := imgutil.GetInfo(extraDiskPath)
441441
if err != nil {
442442
return fmt.Errorf("failed to run detect disk format %q: %q", diskName, err)
443443
}
444-
if extraDiskFormat != "raw" {
445-
if strings.Contains(extraDiskFormat, string(os.PathSeparator)) {
444+
if extraDiskInfo.Format != "raw" {
445+
if strings.Contains(extraDiskInfo.Format, string(os.PathSeparator)) {
446446
return fmt.Errorf(
447447
"failed to convert disk %q to raw for vz driver because extraDiskFormat %q contains a path separator %q",
448448
diskName,
449-
extraDiskFormat,
449+
extraDiskInfo.Format,
450450
os.PathSeparator,
451451
)
452452
}
453453
rawPath := fmt.Sprintf("%s.raw", extraDiskPath)
454-
oldFormatPath := fmt.Sprintf("%s.%s", extraDiskPath, extraDiskFormat)
454+
oldFormatPath := fmt.Sprintf("%s.%s", extraDiskPath, extraDiskInfo.Format)
455455
if err = imgutil.ConvertToRaw(extraDiskPath, rawPath); err != nil {
456-
return fmt.Errorf("failed to convert %s disk %q to raw for vz driver: %w", extraDiskFormat, diskName, err)
456+
return fmt.Errorf("failed to convert %s disk %q to raw for vz driver: %w", extraDiskInfo.Format, diskName, err)
457457
}
458458
if err = os.Rename(extraDiskPath, oldFormatPath); err != nil {
459459
return fmt.Errorf("failed to rename additional disk for vz driver: %w", err)

0 commit comments

Comments
 (0)