blob: c489cf376a9c5ea7d2d44db322b21eee44f16491 [file] [edit]
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package tools
import (
"io/ioutil"
"os"
"path/filepath"
"testing"
)
func TestAppendDMEntryToGRUB(t *testing.T) {
tests := []struct {
name string
initialConfig string
grubName string
partUUID string
hash string
salt string
oemFSSize4K uint64
wantConfig string
wantErr bool
}{
{
name: "V0 (dm=)",
initialConfig: `menuentry "COS" {
linux /boot/vmlinuz root=/dev/dm-0 dm="1 vroot none ro 1,0 4077568 verity payload=PARTUUID=1234 hashtree=PARTUUID=1234 hashstart=4077568 alg=sha256 root_hexdigest=hash0 salt=salt0"
}`,
grubName: "oemroot",
partUUID: "oem-uuid",
hash: "oem-hash",
salt: "oem-salt",
oemFSSize4K: 1000,
wantConfig: `menuentry "COS" {
linux /boot/vmlinuz root=/dev/dm-0 dm="2 vroot none ro 1,0 4077568 verity payload=PARTUUID=1234 hashtree=PARTUUID=1234 hashstart=4077568 alg=sha256 root_hexdigest=hash0 salt=salt0,oemroot none ro 1, 0 8000 verity payload=PARTUUID=oem-uuid hashtree=PARTUUID=oem-uuid hashstart=8000 alg=sha256 root_hexdigest=oem-hash salt=oem-salt"
}`,
wantErr: false,
},
{
name: "V1 (dm-mod.create=)",
initialConfig: `menuentry "COS" {
linux /boot/vmlinuz root=/dev/dm-0 dm-mod.create="vroot,,,ro,0 4077568 verity 0 PARTUUID=1234 PARTUUID=1234 4096 4096 509696 509696 sha256 hash0 salt0"
}`,
grubName: "oemroot",
partUUID: "oem-uuid",
hash: "oem-hash",
salt: "oem-salt",
oemFSSize4K: 1000,
wantConfig: `menuentry "COS" {
linux /boot/vmlinuz root=/dev/dm-0 dm-mod.create="vroot,,,ro,0 4077568 verity 0 PARTUUID=1234 PARTUUID=1234 4096 4096 509696 509696 sha256 hash0 salt0;oemroot,,,ro,0 8000 verity 0 PARTUUID=oem-uuid PARTUUID=oem-uuid 4096 4096 1000 1000 sha256 oem-hash oem-salt"
}`,
wantErr: false,
},
{
name: "No match",
initialConfig: `menuentry "COS" {
linux /boot/vmlinuz root=/dev/sda3
}`,
grubName: "oemroot",
partUUID: "oem-uuid",
hash: "oem-hash",
salt: "oem-salt",
oemFSSize4K: 1000,
wantConfig: `menuentry "COS" {
linux /boot/vmlinuz root=/dev/sda3
}`,
wantErr: false,
},
{
name: "Multiple matches",
initialConfig: `menuentry "COS A" {
linux /boot/vmlinuz root=/dev/dm-0 dm="1 vroot none ro 1,0 4077568 verity payload=PARTUUID=1234 hashtree=PARTUUID=1234 hashstart=4077568 alg=sha256 root_hexdigest=hash0 salt=salt0"
}
menuentry "COS B" {
linux /boot/vmlinuz root=/dev/dm-0 dm="1 vroot none ro 1,0 4077568 verity payload=PARTUUID=1234 hashtree=PARTUUID=1234 hashstart=4077568 alg=sha256 root_hexdigest=hash0 salt=salt0"
}`,
grubName: "oemroot",
partUUID: "oem-uuid",
hash: "oem-hash",
salt: "oem-salt",
oemFSSize4K: 1000,
wantConfig: `menuentry "COS A" {
linux /boot/vmlinuz root=/dev/dm-0 dm="2 vroot none ro 1,0 4077568 verity payload=PARTUUID=1234 hashtree=PARTUUID=1234 hashstart=4077568 alg=sha256 root_hexdigest=hash0 salt=salt0,oemroot none ro 1, 0 8000 verity payload=PARTUUID=oem-uuid hashtree=PARTUUID=oem-uuid hashstart=8000 alg=sha256 root_hexdigest=oem-hash salt=oem-salt"
}
menuentry "COS B" {
linux /boot/vmlinuz root=/dev/dm-0 dm="2 vroot none ro 1,0 4077568 verity payload=PARTUUID=1234 hashtree=PARTUUID=1234 hashstart=4077568 alg=sha256 root_hexdigest=hash0 salt=salt0,oemroot none ro 1, 0 8000 verity payload=PARTUUID=oem-uuid hashtree=PARTUUID=oem-uuid hashstart=8000 alg=sha256 root_hexdigest=oem-hash salt=oem-salt"
}`,
wantErr: false,
},
{
name: "Pickargs cmdline",
initialConfig: `menuentry "COS" {
linux /boot/vmlinuz root=/dev/dm-0 dm-mod.create="vroot,,,ro,0 4077568 verity 0 PARTUUID=1234 PARTUUID=1234 4096 4096 509696 509696 sha256 hash0 salt0" $cmdline_extra
}`,
grubName: "oemroot",
partUUID: "oem-uuid",
hash: "oem-hash",
salt: "oem-salt",
oemFSSize4K: 1000,
wantConfig: `menuentry "COS" {
linux /boot/vmlinuz root=/dev/dm-0 dm-mod.create="vroot,,,ro,0 4077568 verity 0 PARTUUID=1234 PARTUUID=1234 4096 4096 509696 509696 sha256 hash0 salt0;oemroot,,,ro,0 8000 verity 0 PARTUUID=oem-uuid PARTUUID=oem-uuid 4096 4096 1000 1000 sha256 oem-hash oem-salt" $cmdline_extra
}`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "grub-test")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
grubPath := filepath.Join(tmpDir, "grub.cfg")
err = ioutil.WriteFile(grubPath, []byte(tt.initialConfig), 0644)
if err != nil {
t.Fatalf("failed to write initial grub config: %v", err)
}
err = appendDMEntryToGRUB(grubPath, tt.grubName, tt.partUUID, tt.hash, tt.salt, tt.oemFSSize4K)
if (err != nil) != tt.wantErr {
t.Errorf("appendDMEntryToGRUB() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr {
gotConfig, err := ioutil.ReadFile(grubPath)
if err != nil {
t.Fatalf("failed to read modified grub config: %v", err)
}
if string(gotConfig) != tt.wantConfig {
t.Errorf("appendDMEntryToGRUB() got =\n%s\nwant =\n%s", string(gotConfig), tt.wantConfig)
}
}
})
}
}