|
|
@@ -8,6 +8,9 @@
|
|
|
package unix
|
|
|
|
|
|
import (
|
|
|
+ "errors"
|
|
|
+ "fmt"
|
|
|
+ "strconv"
|
|
|
"syscall"
|
|
|
"unsafe"
|
|
|
)
|
|
|
@@ -16,23 +19,77 @@ const (
|
|
|
_SYS_PLEDGE = 108
|
|
|
)
|
|
|
|
|
|
-// Pledge implements the pledge syscall. For more information see pledge(2).
|
|
|
-func Pledge(promises string, paths []string) error {
|
|
|
- promisesPtr, err := syscall.BytePtrFromString(promises)
|
|
|
+// 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.
|
|
|
+//
|
|
|
+// For more information see pledge(2).
|
|
|
+func Pledge(promises, execpromises string) error {
|
|
|
+ maj, min, err := majmin()
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- promisesUnsafe, pathsUnsafe := unsafe.Pointer(promisesPtr), unsafe.Pointer(nil)
|
|
|
- if paths != nil {
|
|
|
- var pathsPtr []*byte
|
|
|
- if pathsPtr, err = syscall.SlicePtrFromStrings(paths); err != nil {
|
|
|
+
|
|
|
+ // 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)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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)
|
|
|
+ }
|
|
|
+
|
|
|
+ pptr, err := syscall.BytePtrFromString(promises)
|
|
|
+ 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
|
|
|
}
|
|
|
- pathsUnsafe = unsafe.Pointer(&pathsPtr[0])
|
|
|
+ expr = unsafe.Pointer(exptr)
|
|
|
}
|
|
|
- _, _, e := syscall.Syscall(_SYS_PLEDGE, uintptr(promisesUnsafe), uintptr(pathsUnsafe), 0)
|
|
|
+
|
|
|
+ _, _, e := syscall.Syscall(_SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)), uintptr(expr), 0)
|
|
|
if e != 0 {
|
|
|
return e
|
|
|
}
|
|
|
+
|
|
|
return nil
|
|
|
}
|
|
|
+
|
|
|
+// majmin returns major and minor version number for an OpenBSD system.
|
|
|
+func majmin() (major int, minor int, err error) {
|
|
|
+ var v Utsname
|
|
|
+ err = Uname(&v)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ major, err = strconv.Atoi(string(v.Release[0]))
|
|
|
+ if err != nil {
|
|
|
+ err = errors.New("cannot parse major version number returned by uname")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ minor, err = strconv.Atoi(string(v.Release[2]))
|
|
|
+ if err != nil {
|
|
|
+ err = errors.New("cannot parse minor version number returned by uname")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ return
|
|
|
+}
|