Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unix: require minimum OpenBSD 6.4 for pledge, unveil #177

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 21 additions & 47 deletions unix/pledge_openbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,43 +14,28 @@ import (

// Pledge implements the pledge syscall.
//
// The pledge syscall does not accept execpromises on OpenBSD releases
// before 6.3.
//
// execpromises must be empty when Pledge is called on OpenBSD
// releases predating 6.3, otherwise an error will be returned.
// This changes both the promises and execpromises; use PledgePromises or
// PledgeExecpromises to only change the promises or execpromises
// respectively.
//
// For more information see pledge(2).
func Pledge(promises, execpromises string) error {
maj, min, err := majmin()
if err != nil {
if err := pledgeAvailable(); err != nil {
return err
}

err = pledgeAvailable(maj, min, execpromises)
pptr, err := syscall.BytePtrFromString(promises)
if err != nil {
return err
}

pptr, err := syscall.BytePtrFromString(promises)
exptr, err := syscall.BytePtrFromString(execpromises)
if err != nil {
return err
}

// This variable will hold either a nil unsafe.Pointer or
// an unsafe.Pointer to a string (execpromises).
var expr unsafe.Pointer

// If we're running on OpenBSD > 6.2, pass execpromises to the syscall.
if maj > 6 || (maj == 6 && min > 2) {
exptr, err := syscall.BytePtrFromString(execpromises)
if err != nil {
return err
}
expr = unsafe.Pointer(exptr)
}

_, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)), uintptr(expr), 0)
_, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)),
uintptr(unsafe.Pointer(exptr)), 0)
if e != 0 {
return e
}
Expand All @@ -64,13 +49,7 @@ func Pledge(promises, execpromises string) error {
//
// For more information see pledge(2).
func PledgePromises(promises string) error {
maj, min, err := majmin()
if err != nil {
return err
}

err = pledgeAvailable(maj, min, "")
if err != nil {
if err := pledgeAvailable(); err != nil {
return err
}

Expand All @@ -82,7 +61,8 @@ func PledgePromises(promises string) error {
return err
}

_, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)), uintptr(expr), 0)
_, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)),
uintptr(expr), 0)
if e != 0 {
return e
}
Expand All @@ -96,13 +76,7 @@ func PledgePromises(promises string) error {
//
// For more information see pledge(2).
func PledgeExecpromises(execpromises string) error {
maj, min, err := majmin()
if err != nil {
return err
}

err = pledgeAvailable(maj, min, execpromises)
if err != nil {
if err := pledgeAvailable(); err != nil {
return err
}

Expand All @@ -114,7 +88,8 @@ func PledgeExecpromises(execpromises string) error {
return err
}

_, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(pptr), uintptr(unsafe.Pointer(exptr)), 0)
_, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(pptr),
uintptr(unsafe.Pointer(exptr)), 0)
if e != 0 {
return e
}
Expand Down Expand Up @@ -147,16 +122,15 @@ func majmin() (major int, minor int, err error) {

// pledgeAvailable checks for availability of the pledge(2) syscall
// based on the running OpenBSD version.
func pledgeAvailable(maj, min int, execpromises string) error {
// If OpenBSD <= 5.9, pledge is not available.
if (maj == 5 && min != 9) || maj < 5 {
return fmt.Errorf("pledge syscall is not available on OpenBSD %d.%d", maj, min)
func pledgeAvailable() error {
maj, min, err := majmin()
if err != nil {
return err
}

// If OpenBSD <= 6.2 and execpromises is not empty,
// return an error - execpromises is not available before 6.3
if (maj < 6 || (maj == 6 && min <= 2)) && execpromises != "" {
return fmt.Errorf("cannot use execpromises on OpenBSD %d.%d", maj, min)
// Require OpenBSD 6.4 as a minimum.
if maj < 6 || (maj == 6 && min <= 3) {
return fmt.Errorf("cannot call Pledge on OpenBSD %d.%d", maj, min)
}

return nil
Expand Down
23 changes: 23 additions & 0 deletions unix/unveil_openbsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package unix

import (
"fmt"
"syscall"
"unsafe"
)
Expand All @@ -14,6 +15,9 @@ import (
// Note that the special case of blocking further
// unveil calls is handled by UnveilBlock.
func Unveil(path string, flags string) error {
if err := supportsUnveil(); err != nil {
return err
}
pathPtr, err := syscall.BytePtrFromString(path)
if err != nil {
return err
Expand All @@ -32,6 +36,9 @@ func Unveil(path string, flags string) error {
// UnveilBlock blocks future unveil calls.
// For more information see unveil(2).
func UnveilBlock() error {
if err := supportsUnveil(); err != nil {
return err
}
// Both pointers must be nil.
var pathUnsafe, flagsUnsafe unsafe.Pointer
_, _, e := syscall.Syscall(SYS_UNVEIL, uintptr(pathUnsafe), uintptr(flagsUnsafe), 0)
Expand All @@ -40,3 +47,19 @@ func UnveilBlock() error {
}
return nil
}

// supportsUnveil checks for availability of the unveil(2) system call based
// on the running OpenBSD version.
func supportsUnveil() error {
maj, min, err := majmin()
if err != nil {
return err
}

// unveil is not available before 6.4
if maj < 6 || (maj == 6 && min <= 3) {
return fmt.Errorf("cannot call Unveil on OpenBSD %d.%d", maj, min)
}

return nil
}