Skip to content

Commit

Permalink
Backports (stable-5.21) (#13951)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomponline authored Aug 20, 2024
2 parents 1217f0e + 941902b commit 2ee582d
Show file tree
Hide file tree
Showing 12 changed files with 85 additions and 17 deletions.
10 changes: 10 additions & 0 deletions doc/api-extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -2441,3 +2441,13 @@ In this scenario, the creation and startup is part of a single background operat
Enables the {config:option}`instance-security:security.devlxd.images` configuration option for virtual machines.
This controls the availability of a `/1.0/images/FINGERPRINT/export` API over `devlxd`.
This can be used by a virtual machine running LXD to access raw images from the host.

## `instance_protection_start`

Enables setting the {config:option}`instance-security:security.protection.start` field which prevents instances
from being started if set to `true`.

## `disk_io_bus_virtio_blk`

Adds a new `virtio-blk` value for `io.bus` on `disk` devices which allows
for the attached disk to be connected to the `virtio-blk` bus.
5 changes: 5 additions & 0 deletions doc/howto/instances_manage.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ Once it is running, you can select the {guilabel}`Terminal` tab to access the in
```
````

### Prevent accidental start of instances

To protect a specific instance from being started, set {config:option}`instance-security:security.protection.start` to `true` for the instance.
See {ref}`instances-configure` for instructions.

(instances-manage-stop)=
## Stop an instance

Expand Down
12 changes: 10 additions & 2 deletions doc/metadata.txt
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ See {ref}`devices-disk-initial-config` for more information.
:required: "no"
:shortdesc: "Bus for the device"
:type: "string"
Possible values are `virtio-scsi` or `nvme`.
Possible values are `virtio-scsi`, `virtio-blk` or `nvme`.
```

```{config:option} io.cache device-disk-device-conf
Expand Down Expand Up @@ -2165,7 +2165,7 @@ See {ref}`container-security` for more information.
```{config:option} security.protection.delete instance-security
:defaultdesc: "`false`"
:liveupdate: "yes"
:shortdesc: "Prevents the instance from being deleted"
:shortdesc: "Whether to prevent the instance from being deleted"
:type: "bool"

```
Expand All @@ -2179,6 +2179,14 @@ See {ref}`container-security` for more information.
Set this option to `true` to prevent the instance's file system from being UID/GID shifted on startup.
```

```{config:option} security.protection.start instance-security
:defaultdesc: "`false`"
:liveupdate: "yes"
:shortdesc: "Whether to prevent the instance from being started"
:type: "bool"

```

```{config:option} security.secureboot instance-security
:condition: "virtual machine"
:defaultdesc: "`true`"
Expand Down
4 changes: 2 additions & 2 deletions lxd/device/disk.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,14 +320,14 @@ func (d *disk) validateConfig(instConf instance.ConfigReader) error {
// shortdesc: Caching mode for the device
"io.cache": validate.Optional(validate.IsOneOf("none", "writeback", "unsafe")),
// lxdmeta:generate(entities=device-disk; group=device-conf; key=io.bus)
// Possible values are `virtio-scsi` or `nvme`.
// Possible values are `virtio-scsi`, `virtio-blk` or `nvme`.
// ---
// type: string
// defaultdesc: `virtio-scsi`
// required: no
// condition: virtual machine
// shortdesc: Bus for the device
"io.bus": validate.Optional(validate.IsOneOf("virtio-scsi", "nvme")),
"io.bus": validate.Optional(validate.IsOneOf("nvme", "virtio-blk", "virtio-scsi")),
}

err := d.config.Validate(rules)
Expand Down
7 changes: 6 additions & 1 deletion lxd/instance/drivers/driver_lxc.go
Original file line number Diff line number Diff line change
Expand Up @@ -2582,6 +2582,11 @@ func (d *lxc) validateStartup(statusCode api.StatusCode) error {
return fmt.Errorf("The image used by this instance requires nesting. Please set security.nesting=true on the instance")
}

// Check if instance is start protected.
if shared.IsTrue(d.expandedConfig["security.protection.start"]) {
return fmt.Errorf("Instance is protected from being started")
}

return nil
}

Expand Down Expand Up @@ -3735,7 +3740,7 @@ func (d *lxc) delete(force bool) error {
}

if !force && shared.IsTrue(d.expandedConfig["security.protection.delete"]) && !d.IsSnapshot() {
err := fmt.Errorf("Instance is protected")
err := fmt.Errorf("Instance is protected from being deleted")
d.logger.Warn("Failed to delete instance", logger.Ctx{"err": err})
return err
}
Expand Down
17 changes: 11 additions & 6 deletions lxd/instance/drivers/driver_qemu.go
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,11 @@ func (d *qemu) validateStartup(stateful bool, statusCode api.StatusCode) error {
return fmt.Errorf("Stateful start requires migration.stateful to be set to true")
}

// Check if instance is start protected.
if shared.IsTrue(d.expandedConfig["security.protection.start"]) {
return fmt.Errorf("Instance is protected from being started")
}

return nil
}

Expand Down Expand Up @@ -3434,9 +3439,9 @@ func (d *qemu) generateQemuConfigFile(cpuInfo *cpuTopology, mountInfo *storagePo
}

qemuDev := make(map[string]string)
if busName == "nvme" {
if shared.ValueInSlice(busName, []string{"nvme", "virtio-blk"}) {
// Allocate a PCI(e) port and write it to the config file so QMP can "hotplug" the
// NVME drive into it later.
// drive into it later.
devBus, devAddr, multi := bus.allocate(busFunctionGroupNone)

// Populate the qemu device with port info.
Expand Down Expand Up @@ -4082,7 +4087,7 @@ func (d *qemu) addDriveConfig(qemuDev map[string]string, bootIndexes map[string]
} else if media == "cdrom" {
qemuDev["driver"] = "scsi-cd"
}
} else if bus == "nvme" {
} else if shared.ValueInSlice(bus, []string{"nvme", "virtio-blk"}) {
if qemuDev["bus"] == "" {
// Figure out a hotplug slot.
pciDevID := qemuPCIDeviceIDStart
Expand All @@ -4099,12 +4104,12 @@ func (d *qemu) addDriveConfig(qemuDev map[string]string, bootIndexes map[string]
}

pciDeviceName := fmt.Sprintf("%s%d", busDevicePortPrefix, pciDevID)
d.logger.Debug("Using PCI bus device to hotplug NVME into", logger.Ctx{"device": driveConf.DevName, "port": pciDeviceName})
d.logger.Debug("Using PCI bus device to hotplug drive into", logger.Ctx{"device": driveConf.DevName, "port": pciDeviceName})
qemuDev["bus"] = pciDeviceName
qemuDev["addr"] = "00.0"
}

qemuDev["driver"] = "nvme"
qemuDev["driver"] = bus
}

if bootIndexes != nil {
Expand Down Expand Up @@ -6114,7 +6119,7 @@ func (d *qemu) delete(force bool) error {

// Check if instance is delete protected.
if !force && shared.IsTrue(d.expandedConfig["security.protection.delete"]) && !d.IsSnapshot() {
return fmt.Errorf("Instance is protected")
return fmt.Errorf("Instance is protected from being deleted")
}

// Delete any persistent warnings for instance.
Expand Down
11 changes: 10 additions & 1 deletion lxd/instance/instancetype/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,18 @@ var InstanceConfigKeysAny = map[string]func(value string) error{
// type: bool
// defaultdesc: `false`
// liveupdate: yes
// shortdesc: Prevents the instance from being deleted
// shortdesc: Whether to prevent the instance from being deleted
"security.protection.delete": validate.Optional(validate.IsBool),

// lxdmeta:generate(entities=instance; group=security; key=security.protection.start)
//
// ---
// type: bool
// defaultdesc: `false`
// liveupdate: yes
// shortdesc: Whether to prevent the instance from being started
"security.protection.start": validate.Optional(validate.IsBool),

// lxdmeta:generate(entities=instance; group=snapshots; key=snapshots.schedule)
// Specify either a cron expression (`<minute> <hour> <dom> <month> <dow>`), a comma-separated list of schedule aliases (`@hourly`, `@daily`, `@midnight`, `@weekly`, `@monthly`, `@annually`, `@yearly`), or leave empty to disable automatic snapshots.
//
Expand Down
7 changes: 5 additions & 2 deletions lxd/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,16 @@ func (slice instanceAutostartList) Swap(i, j int) {
var instancesStartMu sync.Mutex

// instanceShouldAutoStart returns whether the instance should be auto-started.
// Returns true if boot.autostart is enabled or boot.autostart is not set and instance was previously running.
// Returns true if the conditions below are all met:
// 1. security.protection.start is not enabled or not set.
// 2. boot.autostart is enabled or boot.autostart is not set and instance was previously running.
func instanceShouldAutoStart(inst instance.Instance) bool {
config := inst.ExpandedConfig()
autoStart := config["boot.autostart"]
lastState := config["volatile.last_state.power"]
protectStart := config["security.protection.start"]

return shared.IsTrue(autoStart) || (autoStart == "" && lastState == instance.PowerStateRunning)
return shared.IsFalseOrEmpty(protectStart) && (shared.IsTrue(autoStart) || (autoStart == "" && lastState == instance.PowerStateRunning))
}

func instancesStart(s *state.State, instances []instance.Instance) {
Expand Down
13 changes: 11 additions & 2 deletions lxd/metadata/configuration.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
"io.bus": {
"condition": "virtual machine",
"defaultdesc": "`virtio-scsi`",
"longdesc": "Possible values are `virtio-scsi` or `nvme`.",
"longdesc": "Possible values are `virtio-scsi`, `virtio-blk` or `nvme`.",
"required": "no",
"shortdesc": "Bus for the device",
"type": "string"
Expand Down Expand Up @@ -2452,7 +2452,7 @@
"defaultdesc": "`false`",
"liveupdate": "yes",
"longdesc": "",
"shortdesc": "Prevents the instance from being deleted",
"shortdesc": "Whether to prevent the instance from being deleted",
"type": "bool"
}
},
Expand All @@ -2466,6 +2466,15 @@
"type": "bool"
}
},
{
"security.protection.start": {
"defaultdesc": "`false`",
"liveupdate": "yes",
"longdesc": "",
"shortdesc": "Whether to prevent the instance from being started",
"type": "bool"
}
},
{
"security.secureboot": {
"condition": "virtual machine",
Expand Down
2 changes: 1 addition & 1 deletion scripts/bash/lxd-client
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ _have lxc && {
security.devlxd security.devlxd.images \
security.idmap.base security.idmap.isolated security.idmap.size \
security.nesting security.privileged \
security.protection.delete security.protection.shift \
security.protection.delete security.protection.shift security.protection.start\
security.secureboot \
security.sev security.sev.es security.sev.policy.es security.sev.session.dh security.sev.session.data \
security.syscalls.allow \
Expand Down
2 changes: 2 additions & 0 deletions shared/version/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,8 @@ var APIExtensions = []string{
"instance_import_conversion",
"instance_create_start",
"devlxd_images_vm",
"instance_protection_start",
"disk_io_bus_virtio_blk",
}

// APIExtensionsCount returns the number of available API extensions.
Expand Down
12 changes: 12 additions & 0 deletions test/suites/security.sh
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,18 @@ test_security_protection() {

lxc profile unset default security.protection.delete

# Test start protection
lxc profile set default security.protection.start true

lxc init testimage c1
! lxc start c1 || false

lxc config set c1 security.protection.start false
lxc start c1
lxc delete c1 --force

lxc profile unset default security.protection.start

# Test shifting protection

# Respawn LXD with kernel ID shifting support disabled to force manual shifting.
Expand Down

0 comments on commit 2ee582d

Please sign in to comment.