|
1 // Copyright 2016 The Go Authors. All rights reserved. |
|
2 // Use of this source code is governed by a BSD-style |
|
3 // license that can be found in the LICENSE file. |
|
4 |
|
5 package unix |
|
6 |
|
7 import ( |
|
8 "errors" |
|
9 "fmt" |
|
10 "strconv" |
|
11 "syscall" |
|
12 "unsafe" |
|
13 ) |
|
14 |
|
15 // Pledge implements the pledge syscall. |
|
16 // |
|
17 // The pledge syscall does not accept execpromises on OpenBSD releases |
|
18 // before 6.3. |
|
19 // |
|
20 // execpromises must be empty when Pledge is called on OpenBSD |
|
21 // releases predating 6.3, otherwise an error will be returned. |
|
22 // |
|
23 // For more information see pledge(2). |
|
24 func Pledge(promises, execpromises string) error { |
|
25 maj, min, err := majmin() |
|
26 if err != nil { |
|
27 return err |
|
28 } |
|
29 |
|
30 err = pledgeAvailable(maj, min, execpromises) |
|
31 if err != nil { |
|
32 return err |
|
33 } |
|
34 |
|
35 pptr, err := syscall.BytePtrFromString(promises) |
|
36 if err != nil { |
|
37 return err |
|
38 } |
|
39 |
|
40 // This variable will hold either a nil unsafe.Pointer or |
|
41 // an unsafe.Pointer to a string (execpromises). |
|
42 var expr unsafe.Pointer |
|
43 |
|
44 // If we're running on OpenBSD > 6.2, pass execpromises to the syscall. |
|
45 if maj > 6 || (maj == 6 && min > 2) { |
|
46 exptr, err := syscall.BytePtrFromString(execpromises) |
|
47 if err != nil { |
|
48 return err |
|
49 } |
|
50 expr = unsafe.Pointer(exptr) |
|
51 } |
|
52 |
|
53 _, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)), uintptr(expr), 0) |
|
54 if e != 0 { |
|
55 return e |
|
56 } |
|
57 |
|
58 return nil |
|
59 } |
|
60 |
|
61 // PledgePromises implements the pledge syscall. |
|
62 // |
|
63 // This changes the promises and leaves the execpromises untouched. |
|
64 // |
|
65 // For more information see pledge(2). |
|
66 func PledgePromises(promises string) error { |
|
67 maj, min, err := majmin() |
|
68 if err != nil { |
|
69 return err |
|
70 } |
|
71 |
|
72 err = pledgeAvailable(maj, min, "") |
|
73 if err != nil { |
|
74 return err |
|
75 } |
|
76 |
|
77 // This variable holds the execpromises and is always nil. |
|
78 var expr unsafe.Pointer |
|
79 |
|
80 pptr, err := syscall.BytePtrFromString(promises) |
|
81 if err != nil { |
|
82 return err |
|
83 } |
|
84 |
|
85 _, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(unsafe.Pointer(pptr)), uintptr(expr), 0) |
|
86 if e != 0 { |
|
87 return e |
|
88 } |
|
89 |
|
90 return nil |
|
91 } |
|
92 |
|
93 // PledgeExecpromises implements the pledge syscall. |
|
94 // |
|
95 // This changes the execpromises and leaves the promises untouched. |
|
96 // |
|
97 // For more information see pledge(2). |
|
98 func PledgeExecpromises(execpromises string) error { |
|
99 maj, min, err := majmin() |
|
100 if err != nil { |
|
101 return err |
|
102 } |
|
103 |
|
104 err = pledgeAvailable(maj, min, execpromises) |
|
105 if err != nil { |
|
106 return err |
|
107 } |
|
108 |
|
109 // This variable holds the promises and is always nil. |
|
110 var pptr unsafe.Pointer |
|
111 |
|
112 exptr, err := syscall.BytePtrFromString(execpromises) |
|
113 if err != nil { |
|
114 return err |
|
115 } |
|
116 |
|
117 _, _, e := syscall.Syscall(SYS_PLEDGE, uintptr(pptr), uintptr(unsafe.Pointer(exptr)), 0) |
|
118 if e != 0 { |
|
119 return e |
|
120 } |
|
121 |
|
122 return nil |
|
123 } |
|
124 |
|
125 // majmin returns major and minor version number for an OpenBSD system. |
|
126 func majmin() (major int, minor int, err error) { |
|
127 var v Utsname |
|
128 err = Uname(&v) |
|
129 if err != nil { |
|
130 return |
|
131 } |
|
132 |
|
133 major, err = strconv.Atoi(string(v.Release[0])) |
|
134 if err != nil { |
|
135 err = errors.New("cannot parse major version number returned by uname") |
|
136 return |
|
137 } |
|
138 |
|
139 minor, err = strconv.Atoi(string(v.Release[2])) |
|
140 if err != nil { |
|
141 err = errors.New("cannot parse minor version number returned by uname") |
|
142 return |
|
143 } |
|
144 |
|
145 return |
|
146 } |
|
147 |
|
148 // pledgeAvailable checks for availability of the pledge(2) syscall |
|
149 // based on the running OpenBSD version. |
|
150 func pledgeAvailable(maj, min int, execpromises string) error { |
|
151 // If OpenBSD <= 5.9, pledge is not available. |
|
152 if (maj == 5 && min != 9) || maj < 5 { |
|
153 return fmt.Errorf("pledge syscall is not available on OpenBSD %d.%d", maj, min) |
|
154 } |
|
155 |
|
156 // If OpenBSD <= 6.2 and execpromises is not empty, |
|
157 // return an error - execpromises is not available before 6.3 |
|
158 if (maj < 6 || (maj == 6 && min <= 2)) && execpromises != "" { |
|
159 return fmt.Errorf("cannot use execpromises on OpenBSD %d.%d", maj, min) |
|
160 } |
|
161 |
|
162 return nil |
|
163 } |