diff --git a/Dockerfile.dapper b/Dockerfile.dapper index 3dc56203..757fb749 100644 --- a/Dockerfile.dapper +++ b/Dockerfile.dapper @@ -2,7 +2,7 @@ FROM ubuntu:15.10 RUN apt-get update && \ apt-get -y install locales sudo vim less curl wget git rsync build-essential syslinux isolinux xorriso \ - libblkid-dev libmount-dev libselinux1-dev cpio genisoimage qemu-kvm python-pip ca-certificates + libblkid-dev libmount-dev libselinux1-dev cpio genisoimage qemu-kvm python-pip ca-certificates pkg-config RUN locale-gen en_US.UTF-8 ENV LANG en_US.UTF-8 diff --git a/Makefile b/Makefile index 0964f695..cb2d0dde 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,9 @@ assets/docker: curl -L "$(DOCKER_BINARY_URL)" > $@ chmod +x $@ +assets/selinux/policy.29: + mkdir -p $(dir $@) + curl -L "$(SELINUX_POLICY_URL)" > $@ ifdef COMPILED_KERNEL_URL @@ -43,7 +46,7 @@ $(BUILD)/kernel/: curl -L "$(COMPILED_KERNEL_URL)" | tar -xzf - -C $@ -$(DIST)/artifacts/initrd: bin/ros assets/docker $(BUILD)/kernel/ $(BUILD)/images.tar +$(DIST)/artifacts/initrd: bin/ros assets/docker assets/selinux/policy.29 $(BUILD)/kernel/ $(BUILD)/images.tar mkdir -p $(dir $@) ARCH=$(ARCH) DFS_IMAGE=$(DFS_IMAGE) DEV_BUILD=$(DEV_BUILD) ./scripts/mk-initrd.sh $@ diff --git a/assets/selinux/config b/assets/selinux/config new file mode 100644 index 00000000..35ea6f5e --- /dev/null +++ b/assets/selinux/config @@ -0,0 +1,2 @@ +SELINUX=permissive +SELINUXTYPE=ros diff --git a/assets/selinux/failsafe_context b/assets/selinux/failsafe_context new file mode 100644 index 00000000..b87dbdf0 --- /dev/null +++ b/assets/selinux/failsafe_context @@ -0,0 +1 @@ +system_r:kernel_t:s0 diff --git a/assets/selinux/lxc_contexts b/assets/selinux/lxc_contexts new file mode 100644 index 00000000..bf3fcc1a --- /dev/null +++ b/assets/selinux/lxc_contexts @@ -0,0 +1,3 @@ +process = "system_u:system_r:svirt_lxc_net_t:s0" +content = "system_u:object_r:virt_var_lib_t:s0" +file = "system_u:object_r:svirt_lxc_file_t:s0" diff --git a/assets/selinux/seusers b/assets/selinux/seusers new file mode 100644 index 00000000..1ca7c9ea --- /dev/null +++ b/assets/selinux/seusers @@ -0,0 +1 @@ +__default__:system_u:s0-s0 diff --git a/build.conf b/build.conf index c52b54c8..a95db5f8 100644 --- a/build.conf +++ b/build.conf @@ -1,3 +1,4 @@ IMAGE_NAME=rancher/os VERSION=v0.4.4-dev DFS_IMAGE=rancher/docker:v1.10.1 +SELINUX_POLICY_URL=https://github.com/rancher/refpolicy/releases/download/v0.0.1/policy.29 diff --git a/init/init.go b/init/init.go index ddc9b2ef..59cb5dfd 100644 --- a/init/init.go +++ b/init/init.go @@ -220,6 +220,10 @@ func RunInit() error { return config.LoadConfig() }, loadModules, + func(c *config.CloudConfig) (*config.CloudConfig, error) { + return c, dockerlaunch.PrepareFs(&mountConfig) + }, + initializeSelinux, sysInit, } @@ -236,5 +240,6 @@ func RunInit() error { if err != nil { return err } + return pidOne() } diff --git a/init/selinux.go b/init/selinux.go new file mode 100644 index 00000000..afdfc271 --- /dev/null +++ b/init/selinux.go @@ -0,0 +1,32 @@ +// +build linux + +package init + +import ( + log "github.com/Sirupsen/logrus" + "github.com/rancher/os/config" + "github.com/rancher/os/selinux" + "io/ioutil" +) + +func initializeSelinux(c *config.CloudConfig) (*config.CloudConfig, error) { + ret, _ := selinux.InitializeSelinux() + + if ret != 0 { + log.Debug("Unable to initialize SELinux") + return c, nil + } + + // Set allow_execstack boolean to true + if err := ioutil.WriteFile("/sys/fs/selinux/booleans/allow_execstack", []byte("1"), 0644); err != nil { + log.Debug(err) + return c, nil + } + + if err := ioutil.WriteFile("/sys/fs/selinux/commit_pending_bools", []byte("1"), 0644); err != nil { + log.Debug(err) + return c, nil + } + + return c, nil +} diff --git a/os-config.yml b/os-config.yml index 6f01af2e..886c77c2 100644 --- a/os-config.yml +++ b/os-config.yml @@ -262,6 +262,7 @@ rancher: - /etc/resolv.conf:/etc/resolv.conf - /etc/rkt:/etc/rkt - /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt.rancher + - /etc/selinux:/etc/selinux - /lib/firmware:/lib/firmware - /lib/modules:/lib/modules - /run:/run diff --git a/scripts/mk-initrd.sh b/scripts/mk-initrd.sh index ba52d5f4..fcc6fac9 100755 --- a/scripts/mk-initrd.sh +++ b/scripts/mk-initrd.sh @@ -20,6 +20,7 @@ INITRD_DIR=${BUILD}/initrd rm -rf ${INITRD_DIR}/{usr,init} mkdir -p ${INITRD_DIR}/usr/{bin,share/ros} mkdir -p ${INITRD_DIR}/var/lib/system-docker +mkdir -p ${INITRD_DIR}/usr/etc/selinux/ros/{policy,contexts} if [ "$IS_ROOTFS" == "0" ]; then cp -rf ${BUILD}/kernel/lib ${INITRD_DIR}/usr/ @@ -34,6 +35,12 @@ ln -s usr/bin/ros ${INITRD_DIR}/init ln -s bin ${INITRD_DIR}/usr/sbin ln -s usr/sbin ${INITRD_DIR}/sbin +cp assets/selinux/config ${INITRD_DIR}/usr/etc/selinux/ +cp assets/selinux/policy.29 ${INITRD_DIR}/usr/etc/selinux/ros/policy/ +cp assets/selinux/seusers ${INITRD_DIR}/usr/etc/selinux/ros/ +cp assets/selinux/lxc_contexts ${INITRD_DIR}/usr/etc/selinux/ros/contexts/ +cp assets/selinux/failsafe_context ${INITRD_DIR}/usr/etc/selinux/ros/contexts/ + DFS_ARCH=$(docker create ${DFS_ARCH_IMAGE}) trap "docker rm -fv ${DFS_ARCH}" EXIT diff --git a/selinux/selinux.go b/selinux/selinux.go new file mode 100644 index 00000000..5a1cb2e9 --- /dev/null +++ b/selinux/selinux.go @@ -0,0 +1,13 @@ +// +build linux + +package selinux + +// #cgo pkg-config: libselinux libsepol +// #include +import "C" + +func InitializeSelinux() (int, error) { + enforce := C.int(0) + ret, err := C.selinux_init_load_policy(&enforce) + return int(ret), err +} diff --git a/trash.yml b/trash.yml index dd8b52a2..b499e802 100644 --- a/trash.yml +++ b/trash.yml @@ -66,7 +66,7 @@ import: version: 1349b37bd56f4f5ce2690b5b2c0f53f88a261c67 - package: github.com/rancher/docker-from-scratch - version: v1.10.1 + version: 62ceebcf43725e484e598b2879d1aa33b4a5133a - package: github.com/rancher/netconf version: d7d620ef4ea62a9d04b51c7b3d9dc83fe7ffaa1b diff --git a/vendor/github.com/rancher/docker-from-scratch/Dockerfile.dapper b/vendor/github.com/rancher/docker-from-scratch/Dockerfile.dapper index 3894f875..a2e06377 100644 --- a/vendor/github.com/rancher/docker-from-scratch/Dockerfile.dapper +++ b/vendor/github.com/rancher/docker-from-scratch/Dockerfile.dapper @@ -1,5 +1,6 @@ FROM golang:1.5.3 +RUN apt-get update && apt-get -y install libselinux-dev pkg-config RUN curl -o /usr/local/bin/docker -L https://get.docker.com/builds/Linux/x86_64/docker-1.9.1 && \ chmod +x /usr/local/bin/docker diff --git a/vendor/github.com/rancher/docker-from-scratch/scratch.go b/vendor/github.com/rancher/docker-from-scratch/scratch.go index 6ded8bf7..3a5ecf09 100644 --- a/vendor/github.com/rancher/docker-from-scratch/scratch.go +++ b/vendor/github.com/rancher/docker-from-scratch/scratch.go @@ -14,6 +14,7 @@ import ( log "github.com/Sirupsen/logrus" "github.com/docker/libnetwork/resolvconf" + "github.com/rancher/docker-from-scratch/selinux" "github.com/rancher/docker-from-scratch/util" "github.com/rancher/netconf" ) @@ -37,6 +38,9 @@ var ( {"none", "/sys", "sysfs", ""}, {"none", "/sys/fs/cgroup", "tmpfs", ""}, } + optionalMounts = [][]string{ + {"none", "/sys/fs/selinux", "selinuxfs", ""}, + } systemdMounts = [][]string{ {"systemd", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd"}, } @@ -56,6 +60,7 @@ type Config struct { EmulateSystemd bool NoFiles uint64 Environment []string + GraphDirectory string } func createMounts(mounts ...[]string) error { @@ -70,6 +75,16 @@ func createMounts(mounts ...[]string) error { return nil } +func createOptionalMounts(mounts ...[]string) { + for _, mount := range mounts { + log.Debugf("Mounting %s %s %s %s", mount[0], mount[1], mount[2], mount[3]) + err := util.Mount(mount[0], mount[1], mount[2], mount[3]) + if err != nil { + log.Debugf("Unable to mount %s %s %s %s: %s", mount[0], mount[1], mount[2], mount[3], err) + } + } +} + func createDirs(dirs ...string) error { for _, dir := range dirs { if _, err := os.Stat(dir); os.IsNotExist(err) { @@ -213,6 +228,22 @@ func copyDefault(folder, name string) error { return nil } +func copyDefaultFolder(folder string) error { + defaultFolder := path.Join(defaultPrefix, folder) + files, _ := ioutil.ReadDir(defaultFolder) + for _, file := range files { + if file.IsDir() { + continue + } + + if err := copyDefault(folder, file.Name()); err != nil { + return err + } + } + + return nil +} + func defaultFiles(files ...string) error { for _, file := range files { dir := path.Dir(file) @@ -225,6 +256,14 @@ func defaultFiles(files ...string) error { return nil } +func defaultFolders(folders ...string) error { + for _, folder := range folders { + copyDefaultFolder(folder) + } + + return nil +} + func CopyFile(src, folder, name string) error { if _, err := os.Stat(src); os.IsNotExist(err) { return nil @@ -330,6 +369,8 @@ func ParseConfig(config *Config, args ...string) []string { if err != nil { config.BridgeMtu = mtu } + } else if strings.HasPrefix(arg, "-g") || strings.HasPrefix(arg, "--graph") { + config.GraphDirectory = util.GetValue(i, args) } } @@ -363,11 +404,17 @@ func PrepareFs(config *Config) error { return err } + createOptionalMounts(optionalMounts...) + if err := mountCgroups(config.CgroupHierarchy); err != nil { return err } - if err := createLayout(); err != nil { + if err := createLayout(config); err != nil { + return err + } + + if err := firstPrepare(); err != nil { return err } @@ -405,11 +452,23 @@ func touchSockets(args ...string) error { return nil } -func createLayout() error { +func createLayout(config *Config) error { if err := createDirs("/tmp", "/root/.ssh", "/var"); err != nil { return err } + graphDirectory := config.GraphDirectory + + if config.GraphDirectory == "" { + graphDirectory = "/var/lib/docker" + } + + if err := createDirs(graphDirectory); err != nil { + return err + } + + selinux.SetFileContext(graphDirectory, "system_u:object_r:var_lib_t:s0") + return CreateSymlinks([][]string{ {"usr/lib", "/lib"}, {"usr/sbin", "/sbin"}, @@ -417,7 +476,7 @@ func createLayout() error { }) } -func prepare(config *Config, docker string, args ...string) error { +func firstPrepare() error { os.Setenv("PATH", "/sbin:/usr/sbin:/usr/bin") if err := defaultFiles( @@ -428,6 +487,15 @@ func prepare(config *Config, docker string, args ...string) error { return err } + if err := defaultFolders( + "/etc/selinux", + "/etc/selinux/ros", + "/etc/selinux/ros/policy", + "/etc/selinux/ros/contexts", + ); err != nil { + return err + } + if err := createPasswd(); err != nil { return err } @@ -436,6 +504,11 @@ func prepare(config *Config, docker string, args ...string) error { return err } + return nil +} + +func secondPrepare(config *Config, docker string, args ...string) error { + if err := setupNetworking(config); err != nil { return err } @@ -548,7 +621,7 @@ func setUlimit(cfg *Config) error { } func runOrExec(config *Config, docker string, args ...string) (*exec.Cmd, error) { - if err := prepare(config, docker, args...); err != nil { + if err := secondPrepare(config, docker, args...); err != nil { return nil, err } diff --git a/vendor/github.com/rancher/docker-from-scratch/selinux/selinux.go b/vendor/github.com/rancher/docker-from-scratch/selinux/selinux.go new file mode 100644 index 00000000..fe46d482 --- /dev/null +++ b/vendor/github.com/rancher/docker-from-scratch/selinux/selinux.go @@ -0,0 +1,10 @@ +package selinux + +// #cgo pkg-config: libselinux +// #include +import "C" + +func SetFileContext(path string, context string) (int, error) { + ret, err := C.setfilecon(C.CString(path), C.CString(context)) + return int(ret), err +}