mirror of
https://github.com/golang/sys.git
synced 2026-02-09 04:06:04 +03:00
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:
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user