github.com/sdibtacm/sandbox@v0.0.0-20200320120712-60470cf803dc/exec/scmpFilter/scmp.go (about)

     1  package scmpFilter
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"github.com/sdibtacm/sandbox/exec/log"
     8  	"github.com/sdibtacm/sandbox/g"
     9  	"github.com/sdibtacm/sandbox/units/helper"
    10  	"github.com/sdibtacm/sandbox/units/seccomp"
    11  	"io"
    12  	"io/ioutil"
    13  	"os"
    14  	"syscall"
    15  	"unsafe"
    16  )
    17  
    18  const (
    19  	EPERM  = int16(syscall.EPERM)
    20  	ENOSYS = int16(syscall.ENOSYS)
    21  )
    22  
    23  const (
    24  	DEFAULT_KILL   ScmpAction = 0x00
    25  	DEFAULT_TRACE  ScmpAction = 0x01
    26  	DEFAULT_EPERM  ScmpAction = 0x02
    27  	DEFAULT_ENOSYS ScmpAction = 0x03
    28  
    29  	OTHERS_KILL   ScmpAction = 0x10
    30  	OTHERS_TRACE  ScmpAction = 0x11
    31  	OTHERS_EPERM  ScmpAction = 0x12
    32  	OTHERS_ENOSYS ScmpAction = 0x13
    33  )
    34  
    35  var (
    36  	ErrScmpNotAllowDefaultActionAllow = errors.New("only lrun filter can let default action is 'act_allow' ")
    37  )
    38  
    39  type scmpMid struct {
    40  	seccomp.ScmpFilter
    41  }
    42  
    43  type ScmpAction int8
    44  
    45  type ScmpFilterLoadHelper struct {
    46  	Action ScmpAction
    47  
    48  	LrunScmpFilter string // https://github.com/quark-zju/lrun/blob/master/src/seccomp.h
    49  
    50  	Level int
    51  
    52  	ExecvePathPointer unsafe.Pointer
    53  }
    54  
    55  type scmpLoadFilter struct {
    56  	SetPrivs bool
    57  	BPF      *syscall.SockFprog
    58  }
    59  
    60  func GetScmpFilter(helper *ScmpFilterLoadHelper) (filter *scmpLoadFilter, err error) {
    61  	if helper.Level == 0 {
    62  		return nil, nil
    63  	}
    64  
    65  	var scmp *seccomp.ScmpFilter
    66  	defer func() {
    67  		if scmp != nil {
    68  			scmp.Release()
    69  		}
    70  		// we hope will release after function return
    71  	}()
    72  
    73  	if helper.Level == -1 {
    74  		// will load by lrun scmp filter string
    75  		scmp, err = lrunFilterParse(helper)
    76  	} else {
    77  		// load as white list
    78  		scmp, err = nFilterParse(helper)
    79  	}
    80  	if err != nil {
    81  		return
    82  	}
    83  
    84  	midFilter := scmpLoadFilter{}
    85  
    86  	midFilter.SetPrivs = true
    87  	midFilter.BPF, err = scmpToBPF(scmp)
    88  	if err != nil {
    89  		return
    90  	}
    91  
    92  	filter = &midFilter
    93  	return
    94  }
    95  
    96  func nFilterParse(helper *ScmpFilterLoadHelper) (scmp *seccomp.ScmpFilter, err error) {
    97  	if helper.Action&0x10 == 0x10 {
    98  		err = ErrScmpNotAllowDefaultActionAllow
    99  		g.GetLog().Warning("{}", err)
   100  		return
   101  	}
   102  
   103  	switch helper.Action | 0x00 {
   104  	case 0x00:
   105  		scmp, err = seccomp.NewFilter(seccomp.ActKill)
   106  	case 0x01:
   107  		scmp, err = seccomp.NewFilter(seccomp.ActTrace)
   108  	case 0x02:
   109  		scmp, err = seccomp.NewFilter(seccomp.ActErrno.SetReturnCode(EPERM))
   110  	case 0x03:
   111  		scmp, err = seccomp.NewFilter(seccomp.ActErrno.SetReturnCode(ENOSYS))
   112  	}
   113  
   114  	switch helper.Level {
   115  	case 1:
   116  
   117  	}
   118  
   119  	return
   120  }
   121  
   122  func scmpToBPF(filter *seccomp.ScmpFilter) (BPF *syscall.SockFprog, err error) {
   123  
   124  	scmpBPFTempFile, err := ioutil.TempFile("", "sandbox-ScmpBPF-")
   125  	defer func() {
   126  		if scmpBPFTempFile != nil {
   127  			_ = scmpBPFTempFile.Close()
   128  			os.Remove(scmpBPFTempFile.Name())
   129  		}
   130  	}()
   131  
   132  	if err != nil {
   133  		g.GetLog().Warning("can not make bpf temp file with error: {}", err)
   134  		return
   135  	}
   136  
   137  	err = filter.ExportBPF2Fd(scmpBPFTempFile.Fd())
   138  	if err != nil {
   139  		return
   140  	}
   141  	_ = scmpBPFTempFile.Sync()
   142  
   143  	BpfFileStat, _ := scmpBPFTempFile.Stat()
   144  	sockFilterFileSize := BpfFileStat.Size()
   145  	if sockFilterFileSize%8 != 0 {
   146  		err = errors.New("sockFilterFileSize error " + string(sockFilterFileSize))
   147  		return
   148  	}
   149  	sockFilters := make([]syscall.SockFilter, sockFilterFileSize/8)
   150  	var ret = sockFilterFileSize
   151  	ret, err = scmpBPFTempFile.Seek(0, io.SeekStart)
   152  	if err != nil {
   153  		return
   154  	}
   155  	if ret != 0 {
   156  		log.GetLog().Warning("seek fail, ret not at file start, now at:{}", ret)
   157  		err = errors.New("seek fail, ret not at file start")
   158  	}
   159  
   160  	sockFilterFileContent, err := ioutil.ReadAll(scmpBPFTempFile)
   161  	bytesBuffer := bytes.NewBuffer(sockFilterFileContent)
   162  	if helper.IsLittleEndian() {
   163  		err = binary.Read(bytesBuffer, binary.LittleEndian, &sockFilters)
   164  	} else {
   165  		err = binary.Read(bytesBuffer, binary.BigEndian, &sockFilters)
   166  	}
   167  
   168  	BPF = &syscall.SockFprog{
   169  		Len:    uint16(sockFilterFileSize / 8),
   170  		Filter: &sockFilters[0],
   171  	}
   172  	return
   173  }