summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--jail.go194
-rw-r--r--jail_test.go45
2 files changed, 239 insertions, 0 deletions
diff --git a/jail.go b/jail.go
new file mode 100644
index 0000000..e7c67de
--- /dev/null
+++ b/jail.go
@@ -0,0 +1,194 @@
+package jail
+
+// #include <stdio.h>
+// #include <stdlib.h>
+// #include <string.h>
+// #include <sys/param.h>
+// #include <sys/jail.h>
+// #include <sys/uio.h>
+// #include <errno.h>
+//
+// void set_iov_field(struct iovec *iov, int field, void *val, size_t len) {
+// iov[field].iov_base = val;
+// iov[field].iov_len = len;
+// }
+//
+// void *get_iov_field(struct iovec *iov, int field, size_t *len) {
+// *len = iov[field].iov_len;
+// return iov[field].iov_base;
+// }
+//
+// void print_iov(struct iovec *iov, int niov) {
+// for (int i = 0; i < niov; i++) {
+// if (iov[i].iov_base == NULL)
+// fprintf(stderr, "(NULL), %lu\n", iov[i].iov_len);
+// else
+// fprintf(stderr, "%s, %lu\n", iov[i].iov_base, iov[i].iov_len);
+// }
+// }
+//
+// void set_int_val(int *dst, int src) {
+// *dst = src;
+// }
+//
+// int get_errno() {
+// return errno;
+// }
+import "C"
+import "errors"
+import "unsafe"
+
+const (
+ JAIL_CREATE = C.JAIL_CREATE
+ JAIL_UPDATE = C.JAIL_UPDATE
+ JAIL_ATTACH = C.JAIL_ATTACH
+ JAIL_DYING = C.JAIL_DYING
+)
+
+var EPerm = errors.New(C.GoString(C.strerror(C.EPERM)))
+var EFault = errors.New(C.GoString(C.strerror(C.EFAULT)))
+var EInval = errors.New(C.GoString(C.strerror(C.EINVAL)))
+var EAgain = errors.New(C.GoString(C.strerror(C.EAGAIN)))
+var ENoent = errors.New(C.GoString(C.strerror(C.ENOENT)))
+var EExist = errors.New(C.GoString(C.strerror(C.EEXIST)))
+var ENameTooLong = errors.New(C.GoString(C.strerror(C.ENAMETOOLONG)))
+
+func mapToIov(params map[string]interface{}) (unsafe.Pointer, int, []unsafe.Pointer) {
+ var freeList []unsafe.Pointer
+ var i = 0
+
+ iov := C.malloc(C.ulong(C.sizeof_struct_iovec * C.int(len(params)*2)))
+ freeList = append(freeList, iov)
+
+ for k, v := range params {
+ c_key := C.CString(k)
+ freeList = append(freeList, unsafe.Pointer(c_key))
+
+ C.set_iov_field((*C.struct_iovec)(iov), C.int(i), unsafe.Pointer(c_key), C.strlen(c_key)+1)
+ i++
+
+ if v_i, ok := v.(int); ok {
+ c_val := C.malloc(C.sizeof_int)
+ freeList = append(freeList, unsafe.Pointer(c_val))
+
+ C.set_int_val((*C.int)(c_val), C.int(v_i))
+ C.set_iov_field((*C.struct_iovec)(iov), C.int(i), c_val, C.sizeof_int)
+ } else if v_s, ok := v.(string); ok {
+ c_val := C.CString(v_s)
+ freeList = append(freeList, unsafe.Pointer(c_val))
+
+ C.set_iov_field((*C.struct_iovec)(iov), C.int(i), unsafe.Pointer(c_val), C.strlen(c_val)+1)
+ } else if _, ok := v.(bool); ok {
+ C.set_iov_field((*C.struct_iovec)(iov), C.int(i), unsafe.Pointer(nil), C.ulong(0))
+ } else {
+ panic("Unknown type")
+ }
+
+ i++
+ }
+
+ //C.print_iov((*C.struct_iovec)(iov), C.int(len(params)*2))
+
+ return iov, len(params)*2, freeList
+}
+
+func iovToMap(iov unsafe.Pointer, niov int, params map[string]interface{}) {
+ for i := 0; i < len(params)*2; i+=2 {
+ var key *C.char
+ var key_len C.ulong
+ var val unsafe.Pointer
+ var val_len C.ulong
+
+ key = (*C.char)(C.get_iov_field((*C.struct_iovec)(iov), C.int(i+0), &key_len))
+ val = C.get_iov_field((*C.struct_iovec)(iov), C.int(i+1), &val_len)
+
+ go_key := C.GoStringN(key, C.int(key_len))
+ if v, ok := params[go_key]; !ok {
+ if _, ok := v.(int); ok {
+ params[go_key] = int(*(*C.int)(val))
+ } else if _, ok := v.(string); ok {
+ params[go_key] = C.GoStringN((*C.char)(val), C.int(val_len))
+ } else if _, ok := v.(bool); ok {
+ // XXX: noop for now
+ } else {
+ panic("Got unknown type from kernel")
+ }
+ } else {
+ panic("Got unknown key from kernel")
+ }
+ }
+}
+
+func freeIov(freeList []unsafe.Pointer) {
+ for _, e := range freeList {
+ C.free(e)
+ }
+}
+
+func errnoToError() error {
+ errno := C.get_errno()
+
+ if errno == C.EPERM {
+ return EPerm
+ } else if errno == C.EFAULT {
+ return EFault
+ } else if errno == C.EINVAL {
+ return EInval
+ } else if errno == C.EAGAIN {
+ return EAgain
+ } else if errno == C.ENOENT {
+ return ENoent
+ } else if errno == C.EEXIST {
+ return EExist
+ } else if errno == C.ENAMETOOLONG {
+ return ENameTooLong
+ } else {
+ return errors.New("Unknown error")
+ }
+}
+
+func Set(params map[string]interface{}, flags int) (int, error) {
+ iov, niov, freeList := mapToIov(params)
+
+ defer freeIov(freeList)
+
+ ret := C.jail_set((*C.struct_iovec)(iov), C.uint(niov), C.int(flags))
+ if ret == -1 {
+ return 0, errnoToError()
+ }
+
+ return int(ret), nil
+}
+
+func Get(params map[string]interface{}, flags int) (int, error) {
+ iov, niov, freeList := mapToIov(params)
+
+ defer freeIov(freeList)
+
+ ret := C.jail_get((*C.struct_iovec)(iov), C.uint(niov), C.int(flags))
+ if ret == -1 {
+ return 0, errnoToError()
+ }
+
+ iovToMap(iov, niov, params)
+
+ return int(ret), nil
+}
+
+func Attach(jid int) error {
+ ret := C.jail_attach(C.int(jid))
+ if ret == -1 {
+ return errnoToError()
+ }
+
+ return nil
+}
+
+func Remove(jid int) error {
+ ret := C.jail_remove(C.int(jid))
+ if ret == -1 {
+ return errnoToError()
+ }
+
+ return nil
+}
diff --git a/jail_test.go b/jail_test.go
new file mode 100644
index 0000000..1967175
--- /dev/null
+++ b/jail_test.go
@@ -0,0 +1,45 @@
+package jail
+
+import "testing"
+
+func TestIov(t *testing.T) {
+ params := make(map[string]interface{})
+ params["name"] = "test"
+ params["path"] = "/"
+
+ _, niov, fl := mapToIov(params)
+
+ defer freeIov(fl)
+
+ if niov != 4 {
+ t.Error("mapToIov return wrong number of pairs ", niov)
+ }
+}
+
+func TestRemove(t *testing.T) {
+ params := make(map[string]interface{})
+ params["name"] = "test_remove"
+ params["path"] = "/"
+ params["persist"] = true
+
+ jid, err := Set(params, JAIL_CREATE)
+ if err != nil {
+ t.Error("Failed to create jail: ", err.Error())
+ }
+
+ err = Remove(jid)
+ if err != nil {
+ t.Error("Failed to remove jail: ", err.Error())
+ }
+}
+
+func TestCreate(t *testing.T) {
+ params := make(map[string]interface{})
+ params["name"] = "test_create"
+ params["path"] = "/"
+
+ _, err := Set(params, JAIL_CREATE | JAIL_ATTACH)
+ if err != nil {
+ t.Error("Failed to create jail: ", err.Error())
+ }
+}