Skip to content

Commit

Permalink
sbctl: implement landlock sandboxing
Browse files Browse the repository at this point in the history
Signed-off-by: Morten Linderud <[email protected]>
  • Loading branch information
Foxboron committed Jul 28, 2024
1 parent 1454913 commit 68b442b
Show file tree
Hide file tree
Showing 7 changed files with 347 additions and 4 deletions.
20 changes: 17 additions & 3 deletions cmd/sbctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ import (
"github.com/foxboron/sbctl"
"github.com/foxboron/sbctl/config"
"github.com/foxboron/sbctl/logging"
"github.com/foxboron/sbctl/lsm"
"github.com/spf13/afero"
"github.com/spf13/cobra"
)

type CmdOptions struct {
JsonOutput bool
QuietOutput bool
Config string
JsonOutput bool
QuietOutput bool
Config string
DisableLandlock bool
}

type cliCommand struct {
Expand Down Expand Up @@ -56,6 +58,7 @@ func baseFlags(cmd *cobra.Command) {
flags := cmd.PersistentFlags()
flags.BoolVar(&cmdOptions.JsonOutput, "json", false, "Output as json")
flags.BoolVar(&cmdOptions.QuietOutput, "quiet", false, "Mute info from logging")
flags.BoolVar(&cmdOptions.DisableLandlock, "disable-landlock", false, "disable landlock")
flags.StringVarP(&cmdOptions.Config, "config", "", "", "Path to configuration file")

cmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
Expand Down Expand Up @@ -115,8 +118,19 @@ func main() {
UnsetImmutable().
Open(),
}

if cmdOptions.DisableLandlock {
state.Config.Landlock = false
}

ctx := context.WithValue(context.Background(), stateDataKey{}, state)

if state.Config.Landlock {
if err := lsm.RestrictConfigPaths(state.Config); err != nil {
log.Fatal(err)
}
}

// This returns i the flag is not found with a specific error
rootCmd.SetFlagErrorFunc(func(cmd *cobra.Command, err error) error {
cmd.Println(err)
Expand Down
17 changes: 16 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"strings"

"github.com/foxboron/sbctl/fs"
"github.com/landlock-lsm/go-landlock/landlock"

"github.com/foxboron/go-uefi/efi/util"
"github.com/foxboron/go-uefi/efivarfs"
Expand Down Expand Up @@ -49,6 +50,7 @@ func (k *Keys) GetKeysConfigs() []*KeyConfig {
}

type Config struct {
Landlock bool `json:"landlock"`
Keydir string `json:"keydir"`
GUID string `json:"guid"`
FilesDb string `json:"files_db"`
Expand All @@ -73,6 +75,7 @@ func (c *Config) GetGUID(vfs afero.Fs) (*util.EFIGUID, error) {

func MkConfig(dir string) *Config {
conf := &Config{
Landlock: true,
GUID: path.Join(dir, "GUID"),
Keydir: path.Join(dir, "keys"),
FilesDb: path.Join(dir, "files.json"),
Expand Down Expand Up @@ -143,12 +146,24 @@ func (s *State) IsInstalled() bool {
return true
}

func (s *State) HasLandlock() bool {
if !s.Config.Landlock {
return false
}
// Minimal test to check if we have some form of landlock available
// TODO: This is probably not good check.
err := landlock.V1.Restrict(
landlock.RWDirs("/"),
)
return err == nil
}

func (s *State) MarshalJSON() ([]byte, error) {
return json.Marshal(
map[string]any{
"installed": s.IsInstalled(),
// We don't want the config embedded probably
// "landlock": s.HasLandlock(),
"landlock": s.HasLandlock(),
// "config": s.Config,
},
)
Expand Down
6 changes: 6 additions & 0 deletions docs/sbctl.8.txt
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,11 @@ Options
+
Default: /etc/sbctl/sbctl.conf

**--disable-landlock**::
Disables landlock sandboxing in sbctl.
+
See linkman:landlock[7].


Bundles
-------
Expand Down Expand Up @@ -501,6 +506,7 @@ See Also
linkman:bootctl[1]
linkman:jq[1]
linkman:sbctl.conf[5]
linkman:landlock[7]

Authors
-------
Expand Down
275 changes: 275 additions & 0 deletions docs/sbctl.conf.5
Original file line number Diff line number Diff line change
@@ -0,0 +1,275 @@
'\" t
.\" Title: sbctl.conf
.\" Author: [see the "Authors" section]
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
.\" Date: 07/28/2024
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "SBCTL\&.CONF" "5" "07/28/2024" "\ \&" "\ \&"
.\" -----------------------------------------------------------------
.\" * Define some portability stuff
.\" -----------------------------------------------------------------
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\" http://bugs.debian.org/507673
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.\" -----------------------------------------------------------------
.\" * set default formatting
.\" -----------------------------------------------------------------
.\" disable hyphenation
.nh
.\" disable justification (adjust text to left margin only)
.ad l
.\" -----------------------------------------------------------------
.\" * MAIN CONTENT STARTS HERE *
.\" -----------------------------------------------------------------
.SH "NAME"
sbctl.conf \- the sbctl configuration file
.SH "SYNOPSIS"
.sp
/etc/sbctl/sbctl\&.conf
.SH "DESCRIPTION"
.sp
The sbctl configuration file is a YAML file\&. It is read on startup if present\&.
.sp
The file can be used for initial setup of a sbctl installation\&.
.SH "CONFIGURATION DIRECTORIES AND PRECEDENCE"
.sp
The configuration file is currently only read from /etc/sbctl\&. This might change in the future\&.
.SH "OPTIONS"
.PP
\fBkeydir:\fR /path/to/key/dir
.RS 4
Defines the directory where sbctl will look for keys\&.

Default: /var/lib/sbctl/keys
.RE
.PP
\fBguid:\fR /path/to/guid/file
.RS 4
The location of the file that defines the user created GUID\&.

The GUID is used to unique identify the list of certificates stored in the EFI variables\&.

Default: /var/lib/sbctl/GUID
.RE
.PP
\fBfiles_db:\fR /path/to/files/json
.RS 4
The location of the json file storing the files sbctl will sign\&.

Default: /var/lib/sbctl/files\&.json
.RE
.PP
\fBbundles_db:\fR /path/to/bundles/json
.RS 4
The location of the json file storing the bundles sbctl will sign\&.

Default: /var/lib/sbctl/bundles\&.json
.RE
.PP
\fBfiles:\fR [ [\fBpath:\fR /path/to/file \fBoutput:\fR /path/to/output ], \&... ]
.RS 4
A list of files sbctl will sign upon setup\&. It will be used to seed the files_db during initial setup\&.
.PP
\fBpath\fR
.RS 4
Absolute path to a file that sbctl should sign\&.
.RE
.PP
\fBoutput\fR
.RS 4
An optional absolute output path for the signed file\&.
.RE
.RE
.PP
\fBkeys:\fR {\fBpk:\fR {\&...}, \fBkek:\fR {\&...}, \fBdb:\fR {\&...}}
.RS 4
A key\-value pair for all the keys in the key hierarchy used for Secure Boot\&. It is used for the initial bootstrap during setup\&.
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
pk
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
kek
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
db
.RE
.RE
.PP
.RS 4
Each of the hierarchies can specify key type and location for the private key and certificate file independent of each other\&. This allows users to keep some keys on different storage mediums depending on needs\&. An example would be to keep the db key as an unencrypted file easily accessible for signing and the PK on a hardware backed enclave to be better secure the key material\&.
.PP
\fBprivkey:\fR /path/to/privatekey/file
.RS 4
Path to the private key\&.

Defaults:
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
\fBpk:\fR
/var/lib/sbctl/keys/PK/PK\&.key
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
\fBkek:\fR
/var/lib/sbctl/keys/KEK/KEK\&.key
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
\fBdb\fR: /var/lib/sbctl/keys/db/db\&.key
.RE
.RE
.PP
\fBpubkey:\fR /path/to/certificate/file
.RS 4
Path to the public key\&.

Default:
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
\fBpk:\fR
/var/lib/sbctl/keys/PK/PK\&.pem
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
\fBkek:\fR
/var/lib/sbctl/keys/KEK/KEK\&.pem
.RE
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
\fBdb\fR: /var/lib/sbctl/keys/db/db\&.pem
.RE
.RE
.PP
\fBtype:\fR file
.RS 4
The type of key used for this signing key\&.

Only the key type of
\fBfile\fR
is currently supported by sbctl\&.

Default: file
.RE
.RE
.SH "EXAMPLE"
.sp
An example of a /etc/sbctl/sbctl\&.conf file with the default values\&.
.sp
.if n \{\
.RS 4
.\}
.nf
\-\-\-
keydir: /var/lib/sbctl/keys
guid: /var/lib/sbctl/GUID
files_db: /var/lib/sbctl/files\&.json
bundles_db: /var/lib/sbctl/bundles\&.json
files:
\- path: /boot/vmlinuz\-linux
output: /boot/vmlinuz\-linux
\- path: /efi/EFI/Linux/arch\-linux\&.efi
output: /efi/EFI/Linux/arch\-linux\&.efi
keys:
pk:
privkey: /var/lib/sbctl/keys/PK/PK\&.key
pubkey: /var/lib/sbctl/keys/PK/PK\&.pem
type: file
kek:
privkey: /var/lib/sbctl/keys/KEK/KEK\&.key
pubkey: /var/lib/sbctl/keys/KEK/KEK\&.pem
type: file
db:
privkey: /var/lib/sbctl/keys/db/db\&.key
pubkey: /var/lib/sbctl/keys/db/db\&.pem
type: file
.fi
.if n \{\
.RE
.\}
.SH "SEE ALSO"
.sp
\fBsbctl\fR(8)
.SH "AUTHORS"
.sp
.RS 4
.ie n \{\
\h'-04'\(bu\h'+03'\c
.\}
.el \{\
.sp -1
.IP \(bu 2.3
.\}
Morten Linderud <morten@linderud\&.pw>
.RE
Loading

0 comments on commit 68b442b

Please sign in to comment.