unix: use libc stubs for OpenBSD pledge+unveil

For both compatibility and security concerns, it is preferrable to
perform system calls through the libc stubs rather than syscall(2).
Besides making programs resilient to changing system call numbers, it
removes an unnecessary use of the syscall(2) call which, if found by
an attacker, could be abused to perform any system call.

As OpenBSD 6.2 is the oldest supported version of OpenBSD, remove the
handling of pledge on versions prior to this release.

PledgeExecpromises is no longer usable on 6.2, as the execpromises is
treated as required (unlike Pledge, where on 6.2 it is allowed but
must be empty).  The empty execpromises string is no longer converted
to a nil pointer on 6.2.  This fixes an out-of-bounds read where, on
6.2, an empty string would be passed to the deprecated pledge(2) API,
which would interpret the pointer as an array of strings.
This commit is contained in:
Josh Rickmar
2023-11-02 01:18:47 +00:00
parent 249e16f7ca
commit 504bf5bfeb
7 changed files with 97 additions and 52 deletions

View File

@@ -8,8 +8,6 @@ import (
"errors"
"fmt"
"strconv"
"syscall"
"unsafe"
)
// Pledge implements the pledge syscall.
@@ -24,23 +22,17 @@ func Pledge(promises, execpromises string) error {
return err
}
pptr, err := syscall.BytePtrFromString(promises)
pptr, err := BytePtrFromString(promises)
if err != nil {
return err
}
exptr, err := syscall.BytePtrFromString(execpromises)
exptr, err := BytePtrFromString(execpromises)
if err != nil {
return err
}
_, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)),
uintptr(unsafe.Pointer(exptr)), 0)
if e != 0 {
return e
}
return nil
return pledge(pptr, exptr)
}
// PledgePromises implements the pledge syscall.
@@ -53,48 +45,33 @@ func PledgePromises(promises string) error {
return err
}
// This variable holds the execpromises and is always nil.
var expr unsafe.Pointer
pptr, err := syscall.BytePtrFromString(promises)
pptr, err := BytePtrFromString(promises)
if err != nil {
return err
}
_, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)),
uintptr(expr), 0)
if e != 0 {
return e
}
return nil
return pledge(pptr, nil)
}
// PledgeExecpromises implements the pledge syscall.
//
// This changes the execpromises and leaves the promises untouched.
//
// The pledge syscall does not accept execpromises on OpenBSD releases
// before 6.3.
//
// For more information see pledge(2).
func PledgeExecpromises(execpromises string) error {
if err := pledgeAvailable(); err != nil {
return err
}
// This variable holds the promises and is always nil.
var pptr unsafe.Pointer
exptr, err := syscall.BytePtrFromString(execpromises)
exptr, err := BytePtrFromString(execpromises)
if err != nil {
return err
}
_, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(pptr),
uintptr(unsafe.Pointer(exptr)), 0)
if e != 0 {
return e
}
return nil
return pledge(nil, exptr)
}
// majmin returns major and minor version number for an OpenBSD system.

View File

@@ -327,3 +327,5 @@ func Uname(uname *Utsname) error {
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
//sys munmap(addr uintptr, length uintptr) (err error)
//sys utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error)
//sys pledge(promises *byte, execpromises *byte) (err error)
//sys unveil(path *byte, flags *byte) (err error)

View File

@@ -4,48 +4,38 @@
package unix
import (
"fmt"
"syscall"
"unsafe"
)
import "fmt"
// Unveil implements the unveil syscall.
// For more information see unveil(2).
// Note that the special case of blocking further
// unveil calls is handled by UnveilBlock.
//
// Unveil requires OpenBSD 6.4 or later.
func Unveil(path string, flags string) error {
if err := supportsUnveil(); err != nil {
return err
}
pathPtr, err := syscall.BytePtrFromString(path)
pathPtr, err := BytePtrFromString(path)
if err != nil {
return err
}
flagsPtr, err := syscall.BytePtrFromString(flags)
flagsPtr, err := BytePtrFromString(flags)
if err != nil {
return err
}
_, _, e := syscall.Syscall(SYS_UNVEIL, uintptr(unsafe.Pointer(pathPtr)), uintptr(unsafe.Pointer(flagsPtr)), 0)
if e != 0 {
return e
}
return nil
return unveil(pathPtr, flagsPtr)
}
// UnveilBlock blocks future unveil calls.
// For more information see unveil(2).
//
// Unveil requires OpenBSD 6.4 or later.
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)
if e != 0 {
return e
}
return nil
return unveil(nil, nil)
}
// supportsUnveil checks for availability of the unveil(2) system call based

View File

@@ -2228,3 +2228,31 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error
var libc_utimensat_trampoline_addr uintptr
//go:cgo_import_dynamic libc_utimensat utimensat "libc.so"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pledge(promises *byte, execpromises *byte) (err error) {
_, _, e1 := syscall_syscall(libc_pledge_trampoline_addr, uintptr(unsafe.Pointer(promises)), uintptr(unsafe.Pointer(execpromises)), 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_pledge_trampoline_addr uintptr
//go:cgo_import_dynamic libc_pledge pledge "libc.so"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func unveil(path *byte, flags *byte) (err error) {
_, _, e1 := syscall_syscall(libc_unveil_trampoline_addr, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(flags)), 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@@ -672,3 +672,13 @@ TEXT libc_utimensat_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_utimensat(SB)
GLOBL ·libc_utimensat_trampoline_addr(SB), RODATA, $4
DATA ·libc_utimensat_trampoline_addr(SB)/4, $libc_utimensat_trampoline<>(SB)
TEXT libc_pledge_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_pledge(SB)
GLOBL ·libc_pledge_trampoline_addr(SB), RODATA, $4
DATA ·libc_pledge_trampoline_addr(SB)/4, $libc_pledge_trampoline<>(SB)
TEXT libc_unveil_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_unveil(SB)
GLOBL ·libc_unveil_trampoline_addr(SB), RODATA, $4
DATA ·libc_unveil_trampoline_addr(SB)/4, $libc_unveil_trampoline<>(SB)

View File

@@ -2228,3 +2228,31 @@ func utimensat(dirfd int, path string, times *[2]Timespec, flags int) (err error
var libc_utimensat_trampoline_addr uintptr
//go:cgo_import_dynamic libc_utimensat utimensat "libc.so"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func pledge(promises *byte, execpromises *byte) (err error) {
_, _, e1 := syscall_syscall(libc_pledge_trampoline_addr, uintptr(unsafe.Pointer(promises)), uintptr(unsafe.Pointer(execpromises)), 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_pledge_trampoline_addr uintptr
//go:cgo_import_dynamic libc_pledge pledge "libc.so"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func unveil(path *byte, flags *byte) (err error) {
_, _, e1 := syscall_syscall(libc_unveil_trampoline_addr, uintptr(unsafe.Pointer(path)), uintptr(unsafe.Pointer(flags)), 0)
if e1 != 0 {
err = errnoErr(e1)
}
return
}
var libc_unveil_trampoline_addr uintptr
//go:cgo_import_dynamic libc_unveil unveil "libc.so"

View File

@@ -672,3 +672,13 @@ TEXT libc_utimensat_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_utimensat(SB)
GLOBL ·libc_utimensat_trampoline_addr(SB), RODATA, $8
DATA ·libc_utimensat_trampoline_addr(SB)/8, $libc_utimensat_trampoline<>(SB)
TEXT libc_pledge_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_pledge(SB)
GLOBL ·libc_pledge_trampoline_addr(SB), RODATA, $8
DATA ·libc_pledge_trampoline_addr(SB)/8, $libc_pledge_trampoline<>(SB)
TEXT libc_unveil_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_unveil(SB)
GLOBL ·libc_unveil_trampoline_addr(SB), RODATA, $8
DATA ·libc_unveil_trampoline_addr(SB)/8, $libc_unveil_trampoline<>(SB)