hashicorp / hashicorp/packer-plugin-amazon

amazon-ebs: nil pointer dereference (SIGSEGV) when capacity_reservation_id is set without capacity_reservation_preference

Open
#684 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
91
Forks
141
Avg merge
2d 18h
Merged PRs (30d)
3

Description

### Overview

Setting `capacity_reservation_id` (or `capacity_reservation_group_arn`) **without** also
setting `capacity_reservation_preference` causes the `amazon-ebs` builder to panic with a nil
pointer dereference at instance launch. Because `run_config.go` validation treats
`capacity_reservation_id` and `capacity_reservation_preference` as **mutually exclusive**, there
is no configuration in which `capacity_reservation_id` can be used at all — every valid config
that sets it crashes.

### Reproduction

Minimal template (`crash.pkr.hcl`):

```hcl
packer {
required_plugins {
amazon = {
source = "github.com/hashicorp/amazon"
version = "~> 1"
}
}
}

source "amazon-ebs" "t" {
region = "us-west-2"
instance_type = "g4dn.8xlarge"
source_ami = "ami-xxxxxxxxxxxxxxxxx" # any AMI
subnet_id = "subnet-xxxxxxxxxxxxxxxxx"
communicator = "none"
skip_create_ami = true
ami_name = "crash-placeholder"
capacity_reservation_id = "cr-xxxxxxxxxxxxxxxxx" # a real, targeted ODCR in the subnet's AZ
}

build {
sources = ["source.amazon-ebs.t"]
}
```

```
packer init crash.pkr.hcl
packer build crash.pkr.hcl
```

Result — panic at the run-source-instance step:

```
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=... addr=0x0 ...]
... github.com/hashicorp/packer-plugin-amazon/builder/common.(*StepRunSourceInstance).Run
.../builder/common/step_run_source_instance.go:263
```

If you instead add `capacity_reservation_preference = "open"` to try to avoid the crash, the
build fails validation before launch:

```
capacity_reservation_id, capacity_reservation_group_arn and capacity_reservation_preference
are mutually exclusive, only one should be set
```

So the two fields can never be combined, and `capacity_reservation_id` on its own always panics.

### Root cause

In `builder/common/step_run_source_instance.go`, `CapacityReservationSpecification` is only
allocated inside the `CapacityReservationPreference != ""` branch:

```go
if s.CapacityReservationPreference != "" {
runOpts.CapacityReservationSpecification = &ec2.CapacityReservationSpecification{
CapacityReservationPreference: aws.String(s.CapacityReservationPreference),
}
}

if s.CapacityReservationId != "" || s.CapacityReservationGroupArn != "" {
// runOpts.CapacityReservationSpecification is still nil here when only the
// id/group_arn was provided -> nil pointer dereference on the next line.
runOpts.CapacityReservationSpecification.CapacityReservationTarget = &ec2.CapacityReservationTarget{}
if s.CapacityReservationId != "" {
runOpts.CapacityReservationSpecification.CapacityReservationTarget.CapacityReservationId = aws.String(s.CapacityReservationId)
}
if s.CapacityReservationGroupArn != "" {
runOpts.CapacityReservationSpecification.CapacityReservationTarget.CapacityReservationResourceGroupArn = aws.String(s.CapacityReservationGroupArn)
}
}
```

When only `capacity_reservation_id`/`capacity_reservation_group_arn` is set,
`CapacityReservationSpecification` is `nil`, and assigning `.CapacityReservationTarget` on it
dereferences the nil pointer. The one config that would allocate the spec
(`CapacityReservationPreference`) is rejected by `run_config.go` as mutually exclusive with the
target fields, so `capacity_reservation_id` is unusable in every valid configuration.

### Suggested fix

Allocate the specification if it is nil before setting the target, e.g.:

```go
if s.CapacityReservationId != "" || s.CapacityReservationGroupArn != "" {
if runOpts.CapacityReservationSpecification == nil {
runOpts.CapacityReservationSpecification = &ec2.CapacityReservationSpecification{}
}
runOpts.CapacityReservationSpecification.CapacityReservationTarget = &ec2.CapacityReservationTarget{}
...
}
```

(The same construction appears in the spot-instance run step and should be checked there too.)

### Affected versions

- Reproduced on **packer-plugin-amazon v1.3.9** (with Packer 1.13.1) and **v1.8.1** (with Packer 1.15.4).
- The same code structure is present on `main`, so it is not fixed in any released version.

### Environment

- Packer: 1.13.1 and 1.15.4
- packer-plugin-amazon: 1.3.9 and 1.8.1
- Host OS: Linux (amd64)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.