File: efivarfs.go

package info (click to toggle)
golang-github-foxboron-go-uefi 0.0~git20250207.69fb7db-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 9,140 kB
  • sloc: makefile: 29; sh: 14
file content (124 lines) | stat: -rw-r--r-- 2,976 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package efivarfs

import (
	"bytes"
	"crypto"
	"crypto/x509"
	"encoding/binary"
	"fmt"

	"github.com/foxboron/go-uefi/efi/device"
	"github.com/foxboron/go-uefi/efi/signature"
	"github.com/foxboron/go-uefi/efivar"
)

// This is the high-level abstraction of efivarfs. It gives you the easy
// variable access and auxillary functions you should expect from a library like
// this.

type Efivarfs struct {
	EFIVars
}

func Open(e EFIVars) *Efivarfs {
	return &Efivarfs{e}
}

func (e *Efivarfs) GetPK() (*signature.SignatureDatabase, error) {
	var rsb signature.SignatureDatabase
	if err := e.GetVar(efivar.PK, &rsb); err != nil {
		return nil, err
	}
	return &rsb, nil
}

func (e *Efivarfs) GetSetupMode() (bool, error) {
	var rsb efibool
	if err := e.GetVar(efivar.SetupMode, &rsb); err != nil {
		return false, err
	}
	return (bool)(rsb), nil
}

func (e *Efivarfs) GetSecureBoot() (bool, error) {
	var rsb efibool
	if err := e.GetVar(efivar.SecureBoot, &rsb); err != nil {
		return false, err
	}
	return (bool)(rsb), nil
}

func (e *Efivarfs) GetKEK() (*signature.SignatureDatabase, error) {
	var rsb signature.SignatureDatabase
	if err := e.GetVar(efivar.KEK, &rsb); err != nil {
		return nil, err
	}
	return &rsb, nil
}

func (e *Efivarfs) Getdb() (*signature.SignatureDatabase, error) {
	var rsb signature.SignatureDatabase
	if err := e.GetVar(efivar.Db, &rsb); err != nil {
		return nil, err
	}
	return &rsb, nil
}

func (e *Efivarfs) Getdbx() (*signature.SignatureDatabase, error) {
	var rsb signature.SignatureDatabase
	if err := e.GetVar(efivar.Dbx, &rsb); err != nil {
		return nil, err
	}
	return &rsb, nil
}

// Writes a signed variable update
func (e *Efivarfs) WriteSignedUpdate(v efivar.Efivar, m efivar.Marshallable, key crypto.Signer, cert *x509.Certificate) error {
	// The reason why we do this is because we are wrapping a bytes.Butter in a
	// marshaller interface to pass through the layers
	// I haven't decided if this is.. elegant or not.
	_, marshal, err := signature.SignEFIVariable(v, m, key, cert)
	if err != nil {
		return err
	}

	return e.WriteVar(v, marshal)
}

func (e *Efivarfs) GetBootEntry(option string) (*device.EFILoadOption, error) {
	var rsb device.EFILoadOption
	entry := efivar.BootEntry
	entry.Name = option
	if err := e.GetVar(entry, &rsb); err != nil {
		return nil, err
	}
	return &rsb, nil
}

type bootorder []string

func (bo *bootorder) Unmarshal(b *bytes.Buffer) error {
	for i := 0; b.Len() != 0; i += 2 {
		sec := make([]byte, 2)
		b.Read(sec)
		val := binary.BigEndian.Uint16([]byte{sec[1], sec[0]})
		*bo = append(*bo, fmt.Sprintf("Boot%04x", val))
	}
	return nil
}

func (e *Efivarfs) GetBootOrder() []string {
	var rsb bootorder
	if err := e.GetVar(efivar.BootOrder, &rsb); err != nil {
		return nil
	}
	return rsb
}

func (e *Efivarfs) GetLoaderEntrySelected() (string, error) {
	var rsb efivar.Efistring
	if err := e.GetVar(efivar.LoaderEntrySelected, &rsb); err != nil {
		return "", err
	}
	return string(rsb), nil
}