Skip to content

Commit ec0a813

Browse files
committed
feat: unify cmdline handling GRUB/systemd-boot
Use cmdline from the UKI in Talos 1.12+ by default for new installs. This brings GRUB in line with systemd-boot vs. cmdline behavior. Fixes #12019 Signed-off-by: Andrey Smirnov <andrey.smirnov@siderolabs.com>
1 parent 37e4c40 commit ec0a813

File tree

35 files changed

+248
-114
lines changed

35 files changed

+248
-114
lines changed

cmd/installer/cmd/installer/install.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ func init() {
3232
rootCmd.AddCommand(installCmd)
3333
}
3434

35+
//nolint:gocyclo
3536
func runInstallCmd(ctx context.Context) (err error) {
3637
log.Printf("running Talos installer %s", version.NewVersion().Tag)
3738

@@ -50,6 +51,9 @@ func runInstallCmd(ctx context.Context) (err error) {
5051
if err != nil {
5152
if errors.Is(err, configloader.ErrNoConfig) {
5253
log.Printf("machine configuration missing, skipping validation")
54+
55+
// machine configuration can be only missing while running an upgrade in maintenance mode, assume that we should follow GrubUseUKICmdline
56+
options.GrubUseUKICmdline = true
5357
} else {
5458
return fmt.Errorf("error loading machine configuration: %w", err)
5559
}
@@ -72,6 +76,10 @@ func runInstallCmd(ctx context.Context) (err error) {
7276
if config.Machine() != nil && config.Machine().Install().LegacyBIOSSupport() {
7377
options.LegacyBIOSSupport = true
7478
}
79+
80+
if config.Machine() != nil && config.Machine().Install().GrubUseUKICmdline() {
81+
options.GrubUseUKICmdline = true
82+
}
7583
}
7684

7785
return install.Install(ctx, p, mode, options)

cmd/installer/pkg/install/install.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ type Options struct {
5353
Force bool
5454
Zero bool
5555
LegacyBIOSSupport bool
56+
GrubUseUKICmdline bool
5657
MetaValues MetaValues
5758
OverlayInstaller overlay.Installer[overlay.ExtraOptions]
5859
OverlayName string
@@ -118,6 +119,7 @@ func Install(ctx context.Context, p runtime.Platform, mode Mode, opts *Options)
118119
opts.ExtraOptions = extraOptions
119120
}
120121

122+
// NOTE: this is legacy code which is only used when running in GRUB mode with GrubUseUKICmdline set to false.
121123
cmdline := procfs.NewCmdline("")
122124
cmdline.Append(constants.KernelParamPlatform, p.Name())
123125

@@ -347,15 +349,16 @@ func (i *Installer) Install(ctx context.Context, mode Mode) (err error) {
347349

348350
// Install the bootloader.
349351
bootInstallResult, err := bootlder.Install(bootloaderoptions.InstallOptions{
350-
BootDisk: i.options.Disk,
351-
Arch: i.options.Arch,
352-
Cmdline: i.cmdline.String(),
353-
Version: i.options.Version,
354-
ImageMode: mode.IsImage(),
355-
MountPrefix: i.options.MountPrefix,
356-
BootAssets: i.options.BootAssets,
357-
Printf: i.options.Printf,
358-
BlkidInfo: info,
352+
BootDisk: i.options.Disk,
353+
Arch: i.options.Arch,
354+
Cmdline: i.cmdline.String(),
355+
GrubUseUKICmdline: i.options.GrubUseUKICmdline,
356+
Version: i.options.Version,
357+
ImageMode: mode.IsImage(),
358+
MountPrefix: i.options.MountPrefix,
359+
BootAssets: i.options.BootAssets,
360+
Printf: i.options.Printf,
361+
BlkidInfo: info,
359362

360363
ExtraInstallStep: func() error {
361364
if i.options.Board != constants.BoardNone {

cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/common.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ func (m *Maker[T]) initVersionContract() error {
211211
// logic has been run.
212212
func (m *Maker[T]) GetClusterConfigs() (clusterops.ClusterConfigs, error) {
213213
// These options needs to be generated after the implementing maker has made changes to the cluster request.
214-
m.GenOps = slices.Concat(m.GenOps, m.Provisioner.GenOptions(m.ClusterRequest.Network))
214+
m.GenOps = slices.Concat(m.GenOps, m.Provisioner.GenOptions(m.ClusterRequest.Network, m.VersionContract))
215215
m.GenOps = slices.Concat(m.GenOps, []generate.Option{generate.WithEndpointList(m.Endpoints)})
216216

217217
m.ConfigBundleOps = append(m.ConfigBundleOps,

cmd/talosctl/cmd/mgmt/cluster/create/clusterops/configmaker/internal/makers/common_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ type testProvisioner struct {
2424
provision.Provisioner
2525
}
2626

27-
func (p testProvisioner) GenOptions(r provision.NetworkRequest) []generate.Option {
27+
func (p testProvisioner) GenOptions(r provision.NetworkRequest, _ *config.VersionContract) []generate.Option {
2828
return []generate.Option{func(o *generate.Options) error { return nil }}
2929
}
3030

hack/release.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,16 @@ Additionally `talosctl image cache-create` has some changes:
125125
Talos now supports optionally disabling kernel module signature verification by setting `module.sig_enforce=0` kernel parameter.
126126
By default module signature verification is enabled (`module.sig_enforce=1`).
127127
When using Factory or Imager supply as `-module.sig_enfore module.sig_enforce=0` kernel parameters to disable module signature enforcement.
128+
"""
129+
130+
[notes.grub]
131+
title = "GRUB"
132+
description = """\
133+
Talos Linux introduces new machine configuration option `.machine.install.grubUseUKICmdline` to control whether GRUB should use the kernel command line
134+
provided by the boot assets (UKI) or to use the command line constructed by Talos itself (legacy behavior).
135+
136+
This option defaults to `true` for new installations, which means that GRUB will use the command line from the UKI, making it easier to customize kernel parameters via boot asset generation.
137+
For existing installations upgrading to v1.12, this option will default to `false` to preserve the legacy behavior.
128138
"""
129139

130140
[make_deps]

hack/test/e2e-qemu.sh

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -207,17 +207,10 @@ case "${WITH_APPARMOR_LSM_ENABLED:-false}" in
207207
false)
208208
;;
209209
*)
210-
cat <<EOF > "${TMP}/kernel-security.patch"
211-
machine:
212-
install:
213-
extraKernelArgs:
214-
- -selinux
215-
- lsm=lockdown,capability,yama,apparmor,bpf
216-
- apparmor=1
217-
EOF
218-
219-
QEMU_FLAGS+=("--config-patch=@${TMP}/kernel-security.patch")
220-
QEMU_FLAGS+=("--extra-boot-kernel-args=-selinux")
210+
# build disk image with specific kernel args to enable AppArmor LSM
211+
make image-metal PLATFORM=linux/amd64 IMAGER_ARGS="--extra-kernel-arg -selinux --extra-kernel-arg lsm=lockdown,capability,yama,apparmor,bpf --extra-kernel-arg apparmor=1"
212+
213+
QEMU_FLAGS+=("--disk-image-path=_out/metal-amd64.raw.zst" "--skip-injecting-config" "--with-apply-config")
221214
;;
222215
esac
223216

internal/app/machined/pkg/runtime/v1alpha1/bootloader/dual/dual.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package dual
77

88
import (
99
"fmt"
10+
"io"
1011
"os"
1112
"path/filepath"
1213
"strings"
@@ -135,7 +136,18 @@ func (c *Config) installGrub(opts options.InstallOptions) error {
135136
return err
136137
}
137138

138-
if err := grubConfig.Put(grubConfig.Default, opts.Cmdline, opts.Version); err != nil {
139+
cmdline := opts.Cmdline
140+
141+
if opts.GrubUseUKICmdline {
142+
cmdlineBytes, err := io.ReadAll(assetInfo.Cmdline)
143+
if err != nil {
144+
return fmt.Errorf("failed to read cmdline from UKI: %w", err)
145+
}
146+
147+
cmdline = string(cmdlineBytes)
148+
}
149+
150+
if err := grubConfig.Put(grubConfig.Default, cmdline, opts.Version); err != nil {
139151
return err
140152
}
141153

internal/app/machined/pkg/runtime/v1alpha1/bootloader/grub/install.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package grub
66

77
import (
88
"fmt"
9+
"io"
910
"os"
1011
"path/filepath"
1112
"runtime"
@@ -17,6 +18,7 @@ import (
1718
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/mount"
1819
"github.com/siderolabs/talos/internal/app/machined/pkg/runtime/v1alpha1/bootloader/options"
1920
"github.com/siderolabs/talos/internal/pkg/partition"
21+
"github.com/siderolabs/talos/internal/pkg/smbios"
2022
"github.com/siderolabs/talos/internal/pkg/uki"
2123
"github.com/siderolabs/talos/pkg/imager/utils"
2224
"github.com/siderolabs/talos/pkg/machinery/constants"
@@ -94,6 +96,8 @@ func (c *Config) install(opts options.InstallOptions) (*options.InstallResult, e
9496
return nil, err
9597
}
9698

99+
cmdline := opts.Cmdline
100+
97101
// if we have a kernel path, assume that the kernel and initramfs are available
98102
if _, err := os.Stat(opts.BootAssets.KernelPath); err == nil {
99103
if err := utils.CopyFiles(
@@ -109,6 +113,10 @@ func (c *Config) install(opts options.InstallOptions) (*options.InstallResult, e
109113
); err != nil {
110114
return nil, err
111115
}
116+
117+
if opts.GrubUseUKICmdline {
118+
return nil, fmt.Errorf("cannot use UKI cmdline when boot assets are not UKI")
119+
}
112120
} else {
113121
// if the kernel path does not exist, assume that the kernel and initramfs are in the UKI
114122
assetInfo, err := uki.Extract(opts.BootAssets.UKIPath)
@@ -135,9 +143,24 @@ func (c *Config) install(opts options.InstallOptions) (*options.InstallResult, e
135143
); err != nil {
136144
return nil, err
137145
}
146+
147+
if opts.GrubUseUKICmdline {
148+
cmdlineBytes, err := io.ReadAll(assetInfo.Cmdline)
149+
if err != nil {
150+
return nil, fmt.Errorf("failed to read cmdline from UKI: %w", err)
151+
}
152+
153+
cmdline = string(cmdlineBytes)
154+
155+
if extraCmdline, err := smbios.ReadOEMVariable(constants.SDStubCmdlineExtraOEMVar); err == nil {
156+
for _, extra := range extraCmdline {
157+
cmdline += " " + extra
158+
}
159+
}
160+
}
138161
}
139162

140-
if err := c.Put(c.Default, opts.Cmdline, opts.Version); err != nil {
163+
if err := c.Put(c.Default, cmdline, opts.Version); err != nil {
141164
return nil, err
142165
}
143166

internal/app/machined/pkg/runtime/v1alpha1/bootloader/options/options.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ type InstallOptions struct {
1919
BootDisk string
2020
// Target architecture.
2121
Arch string
22-
// Kernel command line (grub only).
22+
// Kernel command line (grub only, and only if GrubUseUKICmdline is false).
2323
Cmdline string
24+
// Whether to use the UKI cmdline instead of building it on the host (grub only).
25+
GrubUseUKICmdline bool
2426
// Talos version.
2527
Version string
2628

internal/app/machined/pkg/runtime/v1alpha1/bootloader/sdboot/sdboot.go

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import (
3030
"github.com/siderolabs/talos/internal/pkg/efivarfs"
3131
mountv3 "github.com/siderolabs/talos/internal/pkg/mount/v3"
3232
"github.com/siderolabs/talos/internal/pkg/partition"
33-
smbiosinternal "github.com/siderolabs/talos/internal/pkg/smbios"
33+
"github.com/siderolabs/talos/internal/pkg/smbios"
3434
"github.com/siderolabs/talos/internal/pkg/uki"
3535
"github.com/siderolabs/talos/pkg/imager/utils"
3636
"github.com/siderolabs/talos/pkg/machinery/constants"
@@ -252,20 +252,9 @@ func (c *Config) KexecLoad(r runtime.Runtime, disk string) error {
252252
}
253253

254254
if !efi.GetSecureBoot() {
255-
smbiosInfo, err := smbiosinternal.GetSMBIOSInfo()
256-
if err == nil {
257-
for _, structure := range smbiosInfo.Structures {
258-
if structure.Header.Type != 11 {
259-
continue
260-
}
261-
262-
const kernelCmdlineExtra = "io.systemd.stub.kernel-cmdline-extra="
263-
264-
for _, s := range structure.Strings {
265-
if strings.HasPrefix(s, kernelCmdlineExtra) {
266-
cmdline.WriteString(" " + s[len(kernelCmdlineExtra):])
267-
}
268-
}
255+
if extraCmdline, err := smbios.ReadOEMVariable(constants.SDStubCmdlineExtraOEMVar); err == nil {
256+
for _, s := range extraCmdline {
257+
cmdline.WriteString(" " + s)
269258
}
270259
}
271260
}

0 commit comments

Comments
 (0)