diff --git a/internal/cli/kraft/run/runner_kraftfile_runtime.go b/internal/cli/kraft/run/runner_kraftfile_runtime.go index 598860012..0a0b8d196 100644 --- a/internal/cli/kraft/run/runner_kraftfile_runtime.go +++ b/internal/cli/kraft/run/runner_kraftfile_runtime.go @@ -10,6 +10,7 @@ import ( "os" "strings" + "github.com/klauspost/cpuid" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" machineapi "kraftkit.sh/api/machine/v1alpha1" @@ -24,6 +25,7 @@ import ( "kraftkit.sh/tui/selection" "kraftkit.sh/unikraft/app" ukarch "kraftkit.sh/unikraft/arch" + "kraftkit.sh/unikraft/export/v0/ukrandom" "kraftkit.sh/unikraft/target" ) @@ -358,6 +360,16 @@ func (runner *runnerKraftfileRuntime) Prepare(ctx context.Context, opts *RunOpti machine.Spec.ApplicationArgs = runtime.Command() } + var kernelArgs []string + if !runtime.KConfig().AllNoOrUnset( + "CONFIG_LIBUKRANDOM", + "CONFIG_LIBUKRANDOM_CMDLINE_INIT", + ) && !(cpuid.CPU.Rdrand() && cpuid.CPU.Rdseed()) { + kernelArgs = append(kernelArgs, ukrandom.ParamRandomSeed.WithValue(ukrandom.NewRandomSeed()).String()) + } + + machine.Spec.KernelArgs = kernelArgs + // If automounting is enabled, and an initramfs is provided, set it as a // volume if a initram has been provided. if runtime.KConfig().AnyYes( diff --git a/internal/cli/kraft/run/runner_kraftfile_unikraft.go b/internal/cli/kraft/run/runner_kraftfile_unikraft.go index ac39cc671..0bf2b9afb 100644 --- a/internal/cli/kraft/run/runner_kraftfile_unikraft.go +++ b/internal/cli/kraft/run/runner_kraftfile_unikraft.go @@ -11,12 +11,14 @@ import ( "slices" "strings" + "github.com/klauspost/cpuid" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" machineapi "kraftkit.sh/api/machine/v1alpha1" volumeapi "kraftkit.sh/api/volume/v1alpha1" "kraftkit.sh/config" "kraftkit.sh/unikraft/app" + "kraftkit.sh/unikraft/export/v0/ukrandom" "kraftkit.sh/unikraft/target" ) @@ -151,6 +153,11 @@ func (runner *runnerKraftfileUnikraft) Prepare(ctx context.Context, opts *RunOpt "CONFIG_LIBVFSCORE_AUTOMOUNT_CI_EINITRD", ) + noRandom := t.KConfig().AllNoOrUnset( + "CONFIG_LIBUKRANDOM", + "CONFIG_LIBUKRANDOM_CMDLINE_INIT", + ) && !(cpuid.CPU.Rdrand() && cpuid.CPU.Rdseed()) + if runner.project.Rootfs() != "" && opts.Rootfs == "" && noEmbedded { opts.Rootfs = runner.project.Rootfs() } @@ -184,6 +191,10 @@ func (runner *runnerKraftfileUnikraft) Prepare(ctx context.Context, opts *RunOpt appArgs = append(appArgs, arg) } + if !noRandom { + kernelArgs = append(kernelArgs, ukrandom.ParamRandomSeed.WithValue(ukrandom.NewRandomSeed()).String()) + } + machine.Spec.KernelArgs = kernelArgs machine.Spec.ApplicationArgs = appArgs diff --git a/internal/cli/kraft/run/runner_package.go b/internal/cli/kraft/run/runner_package.go index 5fd1f7765..15a4908b1 100644 --- a/internal/cli/kraft/run/runner_package.go +++ b/internal/cli/kraft/run/runner_package.go @@ -26,8 +26,10 @@ import ( "kraftkit.sh/tui/processtree" "kraftkit.sh/tui/selection" "kraftkit.sh/unikraft" + "kraftkit.sh/unikraft/export/v0/ukrandom" "kraftkit.sh/unikraft/target" + "github.com/klauspost/cpuid" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -338,6 +340,16 @@ func (runner *runnerPackage) Prepare(ctx context.Context, opts *RunOptions, mach }) } + var kernelArgs []string + if !targ.KConfig().AllNoOrUnset( + "CONFIG_LIBUKRANDOM", + "CONFIG_LIBUKRANDOM_CMDLINE_INIT", + ) && !(cpuid.CPU.Rdrand() && cpuid.CPU.Rdseed()) { + kernelArgs = append(kernelArgs, ukrandom.ParamRandomSeed.WithValue(ukrandom.NewRandomSeed()).String()) + } + + machine.Spec.KernelArgs = kernelArgs + switch v := selected.Metadata().(type) { case *ocispec.Image: if machine.Spec.Env == nil { diff --git a/unikraft/export/v0/ukrandom/library.go b/unikraft/export/v0/ukrandom/library.go new file mode 100644 index 000000000..d9af3212d --- /dev/null +++ b/unikraft/export/v0/ukrandom/library.go @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. +package ukrandom + +const LibraryName = "ukrandom" diff --git a/unikraft/export/v0/ukrandom/params.go b/unikraft/export/v0/ukrandom/params.go new file mode 100644 index 000000000..cfe769574 --- /dev/null +++ b/unikraft/export/v0/ukrandom/params.go @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024, Unikraft GmbH and The KraftKit Authors. +// Licensed under the BSD-3-Clause License (the "License"). +// You may not use this file except in compliance with the License. +package ukrandom + +import ( + "crypto/rand" + "fmt" + "math" + "math/big" + "strings" + + "kraftkit.sh/unikraft/export/v0/ukargparse" +) + +var ParamRandomSeed = ukargparse.NewParamStrSlice("random", "seed", nil) + +// ExportedParams returns the parameters available by this exported library. +func ExportedParams() []ukargparse.Param { + return []ukargparse.Param{ + ParamRandomSeed, + } +} + +// RandomSeed are the 8 ints that are required by the ukrandom library. +type RandomSeed [8]uint32 + +// NewRandomSeed generates a new set of true random integers or nothing if error. +func NewRandomSeed() (random RandomSeed) { + maxUint32 := big.NewInt(math.MaxUint32) + for i := 0; i < 8; i++ { + val, err := rand.Int(rand.Reader, maxUint32) + if err != nil { + return RandomSeed{} + } + random[i] = uint32(val.Uint64()) + } + + return random +} + +// String implements fmt.Stringer and returns a valid set of random bytes. +func (rng RandomSeed) String() string { + var sb strings.Builder + + sb.WriteString("[ ") + for i := 0; i < 8; i++ { + sb.WriteString(fmt.Sprintf("%04x ", rng[i])) + } + sb.WriteString("]") + + return sb.String() +}