Merge pull request 'Added pledge(2) and unveil(2) system calls to improve security on OpenBSD.' (#13) from kvothe/molly-brown:master into master

Reviewed-on: #13
This commit is contained in:
Solderpunk 2023-02-08 17:54:29 +00:00
commit b16a8584a6
4 changed files with 89 additions and 0 deletions

View File

@ -59,6 +59,12 @@ Molly Brown only has a single dependency beyond the Go standard
library, which is [this TOML parsing library, which is [this TOML parsing
library](https://github.com/BurntSushi/toml). library](https://github.com/BurntSushi/toml).
The OpenBSD implementation also uses the [golang.org/x/sys/unix
package](https://godoc.org/golang.org/x/sys/unix) to provide the
[pledge(2)](https://man.openbsd.org/pledge.2) and
[unveil(2)](https://man.openbsd.org/unveil.2) system calls to provide
additional security features.
## Installation ## Installation
The easiest way for now to install Molly Brown is to use the standard The easiest way for now to install Molly Brown is to use the standard

View File

@ -106,6 +106,9 @@ func main() {
} }
}() }()
// Restrict access to the files specified in config
enableSecurityRestrictions(config, errorLog)
// Infinite serve loop // Infinite serve loop
for { for {
conn, err := listener.Accept() conn, err := listener.Accept()

14
security.go Normal file
View File

@ -0,0 +1,14 @@
// +build !openbsd
package main
import (
"log"
)
// Restrict access to the files specified in config in an OS-dependent way.
// This is intended to be called immediately prior to accepting client
// connections and may be used to establish a security "jail" for the molly
// brown executable.
func enableSecurityRestrictions(config Config, errorLog *log.Logger) {
}

66
security_openbsd.go Normal file
View File

@ -0,0 +1,66 @@
package main
import (
"golang.org/x/sys/unix"
"log"
"path/filepath"
)
// Restrict access to the files specified in config in an OS-dependent way.
// The OpenBSD implementation uses pledge(2) and unveil(2) to restrict the
// operations available to the molly brown executable. Please note that (S)CGI
// processes that molly brown spawns or communicates with are unrestricted
// and should pledge their own restrictions and unveil their own files.
func enableSecurityRestrictions(config Config, errorLog *log.Logger) {
// Unveil the configured document base as readable.
log.Println("Unveiling \"" + config.DocBase + "\" as readable.")
err := unix.Unveil(config.DocBase, "r")
if err != nil {
errorLog.Println("Could not unveil DocBase: " + err.Error())
log.Fatal(err)
}
// Unveil cgi path globs as executable.
for _, cgiPath := range config.CGIPaths {
cgiGlobbedPaths, err := filepath.Glob(cgiPath)
for _, cgiGlobbedPath := range cgiGlobbedPaths {
log.Println("Unveiling \"" + cgiGlobbedPath + "\" as executable.")
err = unix.Unveil(cgiGlobbedPath, "rx")
if err != nil {
errorLog.Println("Could not unveil CGIPaths: " + err.Error())
log.Fatal(err)
}
}
}
// Unveil scgi socket paths as readable and writeable.
for _, scgiSocket := range config.SCGIPaths {
log.Println("Unveiling \"" + scgiSocket + "\" as read/write.")
err = unix.Unveil(scgiSocket, "rw")
}
// Finalize the unveil list.
// Any files not whitelisted above won't be accessible to molly brown.
err = unix.UnveilBlock()
if err != nil {
errorLog.Println("Could not block unveil: " + err.Error())
log.Fatal(err)
}
// Pledge to only use stdio, inet, and rpath syscalls.
promises := "stdio inet rpath"
if len(config.CGIPaths) > 0 {
// If CGI paths have been specified, also allow exec syscalls.
promises += " exec proc"
}
if len(config.SCGIPaths) > 0 {
// If SCGI paths have been specified, also allow unix sockets.
promises += " unix"
}
err = unix.PledgePromises(promises)
if err != nil {
errorLog.Println("Could not pledge: " + err.Error())
log.Fatal(err)
}
}