pal_linux.go 3.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
package enclave_runtime_pal // import "github.com/opencontainers/runc/libenclave/internal/runtime/pal"

// #cgo LDFLAGS: -ldl
// #define _GNU_SOURCE
// #include <stdlib.h>
// #include <dlfcn.h>
import "C"

import (
	"fmt"
	"os"
	"path"
	"strings"
	"unsafe"
)

const (
	palPrefix = "liberpal-"
	palSuffix = ".so"
)

func (pal *enclaveRuntimePal) Load(palPath string) (err error) {
	bp := path.Base(palPath)
	if !strings.HasPrefix(bp, palPrefix) {
		return fmt.Errorf("not found pal prefix pattern in pal %s\n", palPath)
	}
	if !strings.HasSuffix(bp, palSuffix) {
		return fmt.Errorf("not found pal suffix pattern in pal %s\n", palPath)
	}
	palName := strings.TrimSuffix(strings.TrimPrefix(bp, palPrefix), palSuffix)

	p := C.CString(palPath)
	defer C.free(unsafe.Pointer(p))
	handle := C.dlmopen(C.LM_ID_NEWLM, p, C.RTLD_LAZY)
	if handle == nil {
		return fmt.Errorf("unable to load pal %s\n", palPath)
	}
	defer func() {
		if err != nil {
			C.dlclose(handle)
		}
	}()

	pal.handle = handle
	pal.name = palName

	if err = pal.getPalApiVersion(); err != nil {
		return err
	}
	return pal.probeApi()
}

func (pal *enclaveRuntimePal) getPalApiVersion() error {
	return pal.getSymbol("version",
		func(sym unsafe.Pointer) error {
			if sym == nil {
				pal.version = 1
			} else {
				ver := *(*uint32)(sym)
				if ver > palApiVersion {
					return fmt.Errorf("unsupported pal api version %d", ver)
				}
				pal.version = ver
			}
			return nil
		},
	)
}

func (pal *enclaveRuntimePal) probeApi() (err error) {
	err = pal.getSymbol("init",
		func(sym unsafe.Pointer) error {
			if sym == nil {
				return fmt.Errorf("unresolved api interface %s_pal_init", pal.name)
			}
			pal.init = sym
			return nil
		},
	)
	if err != nil {
		return err
	}

	err = pal.getSymbol("exec",
		func(sym unsafe.Pointer) error {
			if sym == nil {
				return fmt.Errorf("unresolved api interface %s_pal_exec", pal.name)
			}
			pal.exec = sym
			return nil
		},
	)
	if err != nil {
		return err
	}

	err = pal.getSymbol("kill",
		func(sym unsafe.Pointer) error {
			if sym == nil {
				if pal.version == 1 {
					return nil
				}
				return fmt.Errorf("unresolved api interface %s_pal_kill", pal.name)
			}
			pal.kill = sym
			return nil
		},
	)
	if err != nil {
		return err
	}

	err = pal.getSymbol("destroy",
		func(sym unsafe.Pointer) error {
			if sym == nil {
				return fmt.Errorf("unresolved api interface %s_pal_destroy", pal.name)
			}
			pal.destroy = sym
			return nil
		},
	)
	return err
}

func (pal *enclaveRuntimePal) getSymbol(apiName string, handler func(sym unsafe.Pointer) error) error {
	symName := fmt.Sprintf("%s_pal_%s", pal.name, apiName)
	sn := C.CString(symName)
	defer C.free(unsafe.Pointer(sn))

	sym := C.dlsym(pal.handle, sn)
	return handler(sym)
}

func (pal *enclaveRuntimePal) Name() string {
	return fmt.Sprintf("%s (API version %d)", pal.name, pal.version)
}

func (pal *enclaveRuntimePal) Init(args string, logLevel string) error {
	api := &enclaveRuntimePalApiV1{}
	return api.init(pal.init, args, "off")
}

func (pal *enclaveRuntimePal) Attest() (err error) {
	return nil
}

func (pal *enclaveRuntimePal) Exec(cmd []string, envp []string, stdio [3]*os.File) (int32, error) {
	api := &enclaveRuntimePalApiV1{}
	return api.exec(pal.exec, cmd, envp, stdio)
}

func (pal *enclaveRuntimePal) Kill(sig int, pid int) error {
	if pal.version >= 2 {
		api := &enclaveRuntimePalApiV1{}
		return api.kill(pal.kill, sig, pid)
	}
	return nil
}

func (pal *enclaveRuntimePal) Destroy() error {
	api := &enclaveRuntimePalApiV1{}
	return api.destroy(pal.destroy)
}