Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / seccomp / libseccomp-golang / seccomp_internal.go
1 // +build linux
2
3 // Internal functions for libseccomp Go bindings
4 // No exported functions
5
6 package seccomp
7
8 import (
9         "fmt"
10         "os"
11         "syscall"
12 )
13
14 // Unexported C wrapping code - provides the C-Golang interface
15 // Get the seccomp header in scope
16 // Need stdlib.h for free() on cstrings
17
18 // #cgo pkg-config: libseccomp
19 /*
20 #include <stdlib.h>
21 #include <seccomp.h>
22
23 #if SCMP_VER_MAJOR < 2
24 #error Minimum supported version of Libseccomp is v2.1.0
25 #elif SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 1
26 #error Minimum supported version of Libseccomp is v2.1.0
27 #endif
28
29 #define ARCH_BAD ~0
30
31 const uint32_t C_ARCH_BAD = ARCH_BAD;
32
33 #ifndef SCMP_ARCH_AARCH64
34 #define SCMP_ARCH_AARCH64 ARCH_BAD
35 #endif
36
37 #ifndef SCMP_ARCH_MIPS
38 #define SCMP_ARCH_MIPS ARCH_BAD
39 #endif
40
41 #ifndef SCMP_ARCH_MIPS64
42 #define SCMP_ARCH_MIPS64 ARCH_BAD
43 #endif
44
45 #ifndef SCMP_ARCH_MIPS64N32
46 #define SCMP_ARCH_MIPS64N32 ARCH_BAD
47 #endif
48
49 #ifndef SCMP_ARCH_MIPSEL
50 #define SCMP_ARCH_MIPSEL ARCH_BAD
51 #endif
52
53 #ifndef SCMP_ARCH_MIPSEL64
54 #define SCMP_ARCH_MIPSEL64 ARCH_BAD
55 #endif
56
57 #ifndef SCMP_ARCH_MIPSEL64N32
58 #define SCMP_ARCH_MIPSEL64N32 ARCH_BAD
59 #endif
60
61 #ifndef SCMP_ARCH_PPC
62 #define SCMP_ARCH_PPC ARCH_BAD
63 #endif
64
65 #ifndef SCMP_ARCH_PPC64
66 #define SCMP_ARCH_PPC64 ARCH_BAD
67 #endif
68
69 #ifndef SCMP_ARCH_PPC64LE
70 #define SCMP_ARCH_PPC64LE ARCH_BAD
71 #endif
72
73 #ifndef SCMP_ARCH_S390
74 #define SCMP_ARCH_S390 ARCH_BAD
75 #endif
76
77 #ifndef SCMP_ARCH_S390X
78 #define SCMP_ARCH_S390X ARCH_BAD
79 #endif
80
81 const uint32_t C_ARCH_NATIVE       = SCMP_ARCH_NATIVE;
82 const uint32_t C_ARCH_X86          = SCMP_ARCH_X86;
83 const uint32_t C_ARCH_X86_64       = SCMP_ARCH_X86_64;
84 const uint32_t C_ARCH_X32          = SCMP_ARCH_X32;
85 const uint32_t C_ARCH_ARM          = SCMP_ARCH_ARM;
86 const uint32_t C_ARCH_AARCH64      = SCMP_ARCH_AARCH64;
87 const uint32_t C_ARCH_MIPS         = SCMP_ARCH_MIPS;
88 const uint32_t C_ARCH_MIPS64       = SCMP_ARCH_MIPS64;
89 const uint32_t C_ARCH_MIPS64N32    = SCMP_ARCH_MIPS64N32;
90 const uint32_t C_ARCH_MIPSEL       = SCMP_ARCH_MIPSEL;
91 const uint32_t C_ARCH_MIPSEL64     = SCMP_ARCH_MIPSEL64;
92 const uint32_t C_ARCH_MIPSEL64N32  = SCMP_ARCH_MIPSEL64N32;
93 const uint32_t C_ARCH_PPC          = SCMP_ARCH_PPC;
94 const uint32_t C_ARCH_PPC64        = SCMP_ARCH_PPC64;
95 const uint32_t C_ARCH_PPC64LE      = SCMP_ARCH_PPC64LE;
96 const uint32_t C_ARCH_S390         = SCMP_ARCH_S390;
97 const uint32_t C_ARCH_S390X        = SCMP_ARCH_S390X;
98
99 const uint32_t C_ACT_KILL          = SCMP_ACT_KILL;
100 const uint32_t C_ACT_TRAP          = SCMP_ACT_TRAP;
101 const uint32_t C_ACT_ERRNO         = SCMP_ACT_ERRNO(0);
102 const uint32_t C_ACT_TRACE         = SCMP_ACT_TRACE(0);
103 const uint32_t C_ACT_ALLOW         = SCMP_ACT_ALLOW;
104
105 // If TSync is not supported, make sure it doesn't map to a supported filter attribute
106 // Don't worry about major version < 2, the minimum version checks should catch that case
107 #if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 2
108 #define SCMP_FLTATR_CTL_TSYNC _SCMP_CMP_MIN
109 #endif
110
111 const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT;
112 const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH;
113 const uint32_t C_ATTRIBUTE_NNP     = (uint32_t)SCMP_FLTATR_CTL_NNP;
114 const uint32_t C_ATTRIBUTE_TSYNC   = (uint32_t)SCMP_FLTATR_CTL_TSYNC;
115
116 const int      C_CMP_NE            = (int)SCMP_CMP_NE;
117 const int      C_CMP_LT            = (int)SCMP_CMP_LT;
118 const int      C_CMP_LE            = (int)SCMP_CMP_LE;
119 const int      C_CMP_EQ            = (int)SCMP_CMP_EQ;
120 const int      C_CMP_GE            = (int)SCMP_CMP_GE;
121 const int      C_CMP_GT            = (int)SCMP_CMP_GT;
122 const int      C_CMP_MASKED_EQ     = (int)SCMP_CMP_MASKED_EQ;
123
124 const int      C_VERSION_MAJOR     = SCMP_VER_MAJOR;
125 const int      C_VERSION_MINOR     = SCMP_VER_MINOR;
126 const int      C_VERSION_MICRO     = SCMP_VER_MICRO;
127
128 typedef struct scmp_arg_cmp* scmp_cast_t;
129
130 // Wrapper to create an scmp_arg_cmp struct
131 void*
132 make_struct_arg_cmp(
133                     unsigned int arg,
134                     int compare,
135                     uint64_t a,
136                     uint64_t b
137                    )
138 {
139         struct scmp_arg_cmp *s = malloc(sizeof(struct scmp_arg_cmp));
140
141         s->arg = arg;
142         s->op = compare;
143         s->datum_a = a;
144         s->datum_b = b;
145
146         return s;
147 }
148 */
149 import "C"
150
151 // Nonexported types
152 type scmpFilterAttr uint32
153
154 // Nonexported constants
155
156 const (
157         filterAttrActDefault scmpFilterAttr = iota
158         filterAttrActBadArch scmpFilterAttr = iota
159         filterAttrNNP        scmpFilterAttr = iota
160         filterAttrTsync      scmpFilterAttr = iota
161 )
162
163 const (
164         // An error return from certain libseccomp functions
165         scmpError C.int = -1
166         // Comparison boundaries to check for architecture validity
167         archStart ScmpArch = ArchNative
168         archEnd   ScmpArch = ArchS390X
169         // Comparison boundaries to check for action validity
170         actionStart ScmpAction = ActKill
171         actionEnd   ScmpAction = ActAllow
172         // Comparison boundaries to check for comparison operator validity
173         compareOpStart ScmpCompareOp = CompareNotEqual
174         compareOpEnd   ScmpCompareOp = CompareMaskedEqual
175 )
176
177 var (
178         // Error thrown on bad filter context
179         errBadFilter = fmt.Errorf("filter is invalid or uninitialized")
180         // Constants representing library major, minor, and micro versions
181         verMajor = int(C.C_VERSION_MAJOR)
182         verMinor = int(C.C_VERSION_MINOR)
183         verMicro = int(C.C_VERSION_MICRO)
184 )
185
186 // Nonexported functions
187
188 // Check if library version is greater than or equal to the given one
189 func checkVersionAbove(major, minor, micro int) bool {
190         return (verMajor > major) ||
191                 (verMajor == major && verMinor > minor) ||
192                 (verMajor == major && verMinor == minor && verMicro >= micro)
193 }
194
195 // Init function: Verify library version is appropriate
196 func init() {
197         if !checkVersionAbove(2, 1, 0) {
198                 fmt.Fprintf(os.Stderr, "Libseccomp version too low: minimum supported is 2.1.0, detected %d.%d.%d", C.C_VERSION_MAJOR, C.C_VERSION_MINOR, C.C_VERSION_MICRO)
199                 os.Exit(-1)
200         }
201 }
202
203 // Filter helpers
204
205 // Filter finalizer - ensure that kernel context for filters is freed
206 func filterFinalizer(f *ScmpFilter) {
207         f.Release()
208 }
209
210 // Get a raw filter attribute
211 func (f *ScmpFilter) getFilterAttr(attr scmpFilterAttr) (C.uint32_t, error) {
212         f.lock.Lock()
213         defer f.lock.Unlock()
214
215         if !f.valid {
216                 return 0x0, errBadFilter
217         }
218
219         if !checkVersionAbove(2, 2, 0) && attr == filterAttrTsync {
220                 return 0x0, fmt.Errorf("the thread synchronization attribute is not supported in this version of the library")
221         }
222
223         var attribute C.uint32_t
224
225         retCode := C.seccomp_attr_get(f.filterCtx, attr.toNative(), &attribute)
226         if retCode != 0 {
227                 return 0x0, syscall.Errno(-1 * retCode)
228         }
229
230         return attribute, nil
231 }
232
233 // Set a raw filter attribute
234 func (f *ScmpFilter) setFilterAttr(attr scmpFilterAttr, value C.uint32_t) error {
235         f.lock.Lock()
236         defer f.lock.Unlock()
237
238         if !f.valid {
239                 return errBadFilter
240         }
241
242         if !checkVersionAbove(2, 2, 0) && attr == filterAttrTsync {
243                 return fmt.Errorf("the thread synchronization attribute is not supported in this version of the library")
244         }
245
246         retCode := C.seccomp_attr_set(f.filterCtx, attr.toNative(), value)
247         if retCode != 0 {
248                 return syscall.Errno(-1 * retCode)
249         }
250
251         return nil
252 }
253
254 // DOES NOT LOCK OR CHECK VALIDITY
255 // Assumes caller has already done this
256 // Wrapper for seccomp_rule_add_... functions
257 func (f *ScmpFilter) addRuleWrapper(call ScmpSyscall, action ScmpAction, exact bool, cond C.scmp_cast_t) error {
258         var length C.uint
259         if cond != nil {
260                 length = 1
261         } else {
262                 length = 0
263         }
264
265         var retCode C.int
266         if exact {
267                 retCode = C.seccomp_rule_add_exact_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
268         } else {
269                 retCode = C.seccomp_rule_add_array(f.filterCtx, action.toNative(), C.int(call), length, cond)
270         }
271
272         if syscall.Errno(-1*retCode) == syscall.EFAULT {
273                 return fmt.Errorf("unrecognized syscall")
274         } else if syscall.Errno(-1*retCode) == syscall.EPERM {
275                 return fmt.Errorf("requested action matches default action of filter")
276         } else if retCode != 0 {
277                 return syscall.Errno(-1 * retCode)
278         }
279
280         return nil
281 }
282
283 // Generic add function for filter rules
284 func (f *ScmpFilter) addRuleGeneric(call ScmpSyscall, action ScmpAction, exact bool, conds []ScmpCondition) error {
285         f.lock.Lock()
286         defer f.lock.Unlock()
287
288         if !f.valid {
289                 return errBadFilter
290         }
291
292         if len(conds) == 0 {
293                 if err := f.addRuleWrapper(call, action, exact, nil); err != nil {
294                         return err
295                 }
296         } else {
297                 // We don't support conditional filtering in library version v2.1
298                 if !checkVersionAbove(2, 2, 1) {
299                         return fmt.Errorf("conditional filtering requires libseccomp version >= 2.2.1")
300                 }
301
302                 for _, cond := range conds {
303                         cmpStruct := C.make_struct_arg_cmp(C.uint(cond.Argument), cond.Op.toNative(), C.uint64_t(cond.Operand1), C.uint64_t(cond.Operand2))
304                         defer C.free(cmpStruct)
305
306                         if err := f.addRuleWrapper(call, action, exact, C.scmp_cast_t(cmpStruct)); err != nil {
307                                 return err
308                         }
309                 }
310         }
311
312         return nil
313 }
314
315 // Generic Helpers
316
317 // Helper - Sanitize Arch token input
318 func sanitizeArch(in ScmpArch) error {
319         if in < archStart || in > archEnd {
320                 return fmt.Errorf("unrecognized architecture")
321         }
322
323         if in.toNative() == C.C_ARCH_BAD {
324                 return fmt.Errorf("architecture is not supported on this version of the library")
325         }
326
327         return nil
328 }
329
330 func sanitizeAction(in ScmpAction) error {
331         inTmp := in & 0x0000FFFF
332         if inTmp < actionStart || inTmp > actionEnd {
333                 return fmt.Errorf("unrecognized action")
334         }
335
336         if inTmp != ActTrace && inTmp != ActErrno && (in&0xFFFF0000) != 0 {
337                 return fmt.Errorf("highest 16 bits must be zeroed except for Trace and Errno")
338         }
339
340         return nil
341 }
342
343 func sanitizeCompareOp(in ScmpCompareOp) error {
344         if in < compareOpStart || in > compareOpEnd {
345                 return fmt.Errorf("unrecognized comparison operator")
346         }
347
348         return nil
349 }
350
351 func archFromNative(a C.uint32_t) (ScmpArch, error) {
352         switch a {
353         case C.C_ARCH_X86:
354                 return ArchX86, nil
355         case C.C_ARCH_X86_64:
356                 return ArchAMD64, nil
357         case C.C_ARCH_X32:
358                 return ArchX32, nil
359         case C.C_ARCH_ARM:
360                 return ArchARM, nil
361         case C.C_ARCH_NATIVE:
362                 return ArchNative, nil
363         case C.C_ARCH_AARCH64:
364                 return ArchARM64, nil
365         case C.C_ARCH_MIPS:
366                 return ArchMIPS, nil
367         case C.C_ARCH_MIPS64:
368                 return ArchMIPS64, nil
369         case C.C_ARCH_MIPS64N32:
370                 return ArchMIPS64N32, nil
371         case C.C_ARCH_MIPSEL:
372                 return ArchMIPSEL, nil
373         case C.C_ARCH_MIPSEL64:
374                 return ArchMIPSEL64, nil
375         case C.C_ARCH_MIPSEL64N32:
376                 return ArchMIPSEL64N32, nil
377         case C.C_ARCH_PPC:
378                 return ArchPPC, nil
379         case C.C_ARCH_PPC64:
380                 return ArchPPC64, nil
381         case C.C_ARCH_PPC64LE:
382                 return ArchPPC64LE, nil
383         case C.C_ARCH_S390:
384                 return ArchS390, nil
385         case C.C_ARCH_S390X:
386                 return ArchS390X, nil
387         default:
388                 return 0x0, fmt.Errorf("unrecognized architecture")
389         }
390 }
391
392 // Only use with sanitized arches, no error handling
393 func (a ScmpArch) toNative() C.uint32_t {
394         switch a {
395         case ArchX86:
396                 return C.C_ARCH_X86
397         case ArchAMD64:
398                 return C.C_ARCH_X86_64
399         case ArchX32:
400                 return C.C_ARCH_X32
401         case ArchARM:
402                 return C.C_ARCH_ARM
403         case ArchARM64:
404                 return C.C_ARCH_AARCH64
405         case ArchMIPS:
406                 return C.C_ARCH_MIPS
407         case ArchMIPS64:
408                 return C.C_ARCH_MIPS64
409         case ArchMIPS64N32:
410                 return C.C_ARCH_MIPS64N32
411         case ArchMIPSEL:
412                 return C.C_ARCH_MIPSEL
413         case ArchMIPSEL64:
414                 return C.C_ARCH_MIPSEL64
415         case ArchMIPSEL64N32:
416                 return C.C_ARCH_MIPSEL64N32
417         case ArchPPC:
418                 return C.C_ARCH_PPC
419         case ArchPPC64:
420                 return C.C_ARCH_PPC64
421         case ArchPPC64LE:
422                 return C.C_ARCH_PPC64LE
423         case ArchS390:
424                 return C.C_ARCH_S390
425         case ArchS390X:
426                 return C.C_ARCH_S390X
427         case ArchNative:
428                 return C.C_ARCH_NATIVE
429         default:
430                 return 0x0
431         }
432 }
433
434 // Only use with sanitized ops, no error handling
435 func (a ScmpCompareOp) toNative() C.int {
436         switch a {
437         case CompareNotEqual:
438                 return C.C_CMP_NE
439         case CompareLess:
440                 return C.C_CMP_LT
441         case CompareLessOrEqual:
442                 return C.C_CMP_LE
443         case CompareEqual:
444                 return C.C_CMP_EQ
445         case CompareGreaterEqual:
446                 return C.C_CMP_GE
447         case CompareGreater:
448                 return C.C_CMP_GT
449         case CompareMaskedEqual:
450                 return C.C_CMP_MASKED_EQ
451         default:
452                 return 0x0
453         }
454 }
455
456 func actionFromNative(a C.uint32_t) (ScmpAction, error) {
457         aTmp := a & 0xFFFF
458         switch a & 0xFFFF0000 {
459         case C.C_ACT_KILL:
460                 return ActKill, nil
461         case C.C_ACT_TRAP:
462                 return ActTrap, nil
463         case C.C_ACT_ERRNO:
464                 return ActErrno.SetReturnCode(int16(aTmp)), nil
465         case C.C_ACT_TRACE:
466                 return ActTrace.SetReturnCode(int16(aTmp)), nil
467         case C.C_ACT_ALLOW:
468                 return ActAllow, nil
469         default:
470                 return 0x0, fmt.Errorf("unrecognized action")
471         }
472 }
473
474 // Only use with sanitized actions, no error handling
475 func (a ScmpAction) toNative() C.uint32_t {
476         switch a & 0xFFFF {
477         case ActKill:
478                 return C.C_ACT_KILL
479         case ActTrap:
480                 return C.C_ACT_TRAP
481         case ActErrno:
482                 return C.C_ACT_ERRNO | (C.uint32_t(a) >> 16)
483         case ActTrace:
484                 return C.C_ACT_TRACE | (C.uint32_t(a) >> 16)
485         case ActAllow:
486                 return C.C_ACT_ALLOW
487         default:
488                 return 0x0
489         }
490 }
491
492 // Internal only, assumes safe attribute
493 func (a scmpFilterAttr) toNative() uint32 {
494         switch a {
495         case filterAttrActDefault:
496                 return uint32(C.C_ATTRIBUTE_DEFAULT)
497         case filterAttrActBadArch:
498                 return uint32(C.C_ATTRIBUTE_BADARCH)
499         case filterAttrNNP:
500                 return uint32(C.C_ATTRIBUTE_NNP)
501         case filterAttrTsync:
502                 return uint32(C.C_ATTRIBUTE_TSYNC)
503         default:
504                 return 0x0
505         }
506 }