Home | History | Annotate | Download | only in seccomp-bpf
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
      6 #define SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
      7 
      8 #include <signal.h>
      9 #include <stdint.h>
     10 
     11 #include "base/macros.h"
     12 #include "sandbox/linux/system_headers/linux_signal.h"
     13 #include "sandbox/sandbox_export.h"
     14 
     15 namespace sandbox {
     16 
     17 // This purely static class can be used to perform system calls with some
     18 // low-level control.
     19 class SANDBOX_EXPORT Syscall {
     20  public:
     21   // InvalidCall() invokes Call() with a platform-appropriate syscall
     22   // number that is guaranteed to not be implemented (i.e., normally
     23   // returns -ENOSYS).
     24   // This is primarily meant to be useful for writing sandbox policy
     25   // unit tests.
     26   static intptr_t InvalidCall();
     27 
     28   // System calls can take up to six parameters (up to eight on some
     29   // architectures). Traditionally, glibc
     30   // implements this property by using variadic argument lists. This works, but
     31   // confuses modern tools such as valgrind, because we are nominally passing
     32   // uninitialized data whenever we call through this function and pass less
     33   // than the full six arguments.
     34   // So, instead, we use C++'s template system to achieve a very similar
     35   // effect. C++ automatically sets the unused parameters to zero for us, and
     36   // it also does the correct type expansion (e.g. from 32bit to 64bit) where
     37   // necessary.
     38   // We have to use C-style cast operators as we want to be able to accept both
     39   // integer and pointer types.
     40   template <class T0,
     41             class T1,
     42             class T2,
     43             class T3,
     44             class T4,
     45             class T5,
     46             class T6,
     47             class T7>
     48   static inline intptr_t
     49   Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6, T7 p7) {
     50     return Call(nr,
     51                 (intptr_t)p0,
     52                 (intptr_t)p1,
     53                 (intptr_t)p2,
     54                 (intptr_t)p3,
     55                 (intptr_t)p4,
     56                 (intptr_t)p5,
     57                 (intptr_t)p6,
     58                 (intptr_t)p7);
     59   }
     60 
     61   template <class T0,
     62             class T1,
     63             class T2,
     64             class T3,
     65             class T4,
     66             class T5,
     67             class T6>
     68   static inline intptr_t
     69   Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5, T6 p6) {
     70     return Call(nr,
     71                 (intptr_t)p0,
     72                 (intptr_t)p1,
     73                 (intptr_t)p2,
     74                 (intptr_t)p3,
     75                 (intptr_t)p4,
     76                 (intptr_t)p5,
     77                 (intptr_t)p6,
     78                 0);
     79   }
     80 
     81   template <class T0, class T1, class T2, class T3, class T4, class T5>
     82   static inline intptr_t
     83   Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4, T5 p5) {
     84     return Call(nr,
     85                 (intptr_t)p0,
     86                 (intptr_t)p1,
     87                 (intptr_t)p2,
     88                 (intptr_t)p3,
     89                 (intptr_t)p4,
     90                 (intptr_t)p5,
     91                 0,
     92                 0);
     93   }
     94 
     95   template <class T0, class T1, class T2, class T3, class T4>
     96   static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3, T4 p4) {
     97     return Call(nr, p0, p1, p2, p3, p4, 0, 0, 0);
     98   }
     99 
    100   template <class T0, class T1, class T2, class T3>
    101   static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2, T3 p3) {
    102     return Call(nr, p0, p1, p2, p3, 0, 0, 0, 0);
    103   }
    104 
    105   template <class T0, class T1, class T2>
    106   static inline intptr_t Call(int nr, T0 p0, T1 p1, T2 p2) {
    107     return Call(nr, p0, p1, p2, 0, 0, 0, 0, 0);
    108   }
    109 
    110   template <class T0, class T1>
    111   static inline intptr_t Call(int nr, T0 p0, T1 p1) {
    112     return Call(nr, p0, p1, 0, 0, 0, 0, 0, 0);
    113   }
    114 
    115   template <class T0>
    116   static inline intptr_t Call(int nr, T0 p0) {
    117     return Call(nr, p0, 0, 0, 0, 0, 0, 0, 0);
    118   }
    119 
    120   static inline intptr_t Call(int nr) {
    121     return Call(nr, 0, 0, 0, 0, 0, 0, 0, 0);
    122   }
    123 
    124   // Set the registers in |ctx| to match what they would be after a system call
    125   // returning |ret_val|. |ret_val| must follow the Syscall::Call() convention
    126   // of being -errno on errors.
    127   static void PutValueInUcontext(intptr_t ret_val, ucontext_t* ctx);
    128 
    129  private:
    130   // This performs system call |nr| with the arguments p0 to p7 from a constant
    131   // userland address, which is for instance observable by seccomp-bpf filters.
    132   // The constant userland address from which these system calls are made will
    133   // be returned if |nr| is passed as -1.
    134   // On error, this function will return a value between -1 and -4095 which
    135   // should be interpreted as -errno.
    136   static intptr_t Call(int nr,
    137                        intptr_t p0,
    138                        intptr_t p1,
    139                        intptr_t p2,
    140                        intptr_t p3,
    141                        intptr_t p4,
    142                        intptr_t p5,
    143                        intptr_t p6,
    144                        intptr_t p7);
    145 
    146 #if defined(__mips__)
    147   // This function basically does on MIPS what SandboxSyscall() is doing on
    148   // other architectures. However, because of specificity of MIPS regarding
    149   // handling syscall errors, SandboxSyscall() is made as a wrapper for this
    150   // function in order for SandboxSyscall() to behave more like on other
    151   // architectures on places where return value from SandboxSyscall() is used
    152   // directly (like in most tests).
    153   // The syscall "nr" is called with arguments that are set in an array on which
    154   // pointer "args" points to and an information weather there is an error or no
    155   // is returned to SandboxSyscall() by err_stat.
    156   static intptr_t SandboxSyscallRaw(int nr,
    157                                     const intptr_t* args,
    158                                     intptr_t* err_stat);
    159 #endif  // defined(__mips__)
    160 
    161   DISALLOW_IMPLICIT_CONSTRUCTORS(Syscall);
    162 };
    163 
    164 }  // namespace sandbox
    165 
    166 #endif  // SANDBOX_LINUX_SECCOMP_BPF_SYSCALL_H__
    167