1
0
Fork 0
molly-brown/security_openbsd.go
Solderpunk eb85a6e94c Another big refactor, splitting the Config struct in two.
The split reflects that between variables which can and cannot be
overridden by .molly files, and this greatly simplifies the
processing of said files, getting rid of the need for lots of
ugly temporary variable thrashing.
2023-02-25 11:29:13 +01:00

77 lines
2.2 KiB
Go

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 SysConfig, ui userInfo) error {
// Setuid to an unprivileged user
err := DropPrivs(ui)
if err != nil {
return err
}
// Unveil the configured document base as readable.
log.Println("Unveiling \"" + config.DocBase + "\" as readable.")
err = unix.Unveil(config.DocBase, "r")
if err != nil {
log.Println("Could not unveil DocBase: " + err.Error())
return 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 {
log.Println("Could not unveil CGIPaths: " + err.Error())
return 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")
if err != nil {
return err
}
}
// Finalize the unveil list.
// Any files not whitelisted above won't be accessible to molly brown.
err = unix.UnveilBlock()
if err != nil {
log.Println("Could not block unveil: " + err.Error())
return 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 {
log.Println("Could not pledge: " + err.Error())
return err
}
return nil
}