func Main(mode int) { log := createLogger() config, err := loadConfig() if err != nil { log.Error("Could not load configuration: %s\n", oz.DefaultConfigPath, err) os.Exit(1) } fsys := fs.NewFilesystem(config, log) for fii, fpath := range os.Args { if fii == 0 { continue } if !strings.HasPrefix(fpath, "/home/") { log.Warning("Ignored `%s`, only files inside of home are permitted!", fpath) continue } switch mode { case MOUNT: mount(fpath, fsys, log) case UMOUNT: unmount(fpath, fsys, log) } } os.Exit(0) }
func parseArgs() *initState { log := createLogger() if os.Getuid() != 0 { log.Error("oz-init must run as root\n") os.Exit(1) } if os.Getpid() != 1 { log.Error("oz-init must be launched in new pid namespace.") os.Exit(1) } initData := new(InitData) if err := json.NewDecoder(os.Stdin).Decode(&initData); err != nil { log.Error("unable to decode init data: %v", err) os.Exit(1) } log.Debug("Init state: %+v", initData) if (initData.User.Uid != strconv.Itoa(int(initData.Uid))) || (initData.Uid == 0) { log.Error("invalid uid or user passed to init.") os.Exit(1) } env := []string{} env = append(env, initData.LaunchEnv...) env = append(env, "PATH=/usr/bin:/bin") if initData.Profile.XServer.Enabled { env = append(env, "DISPLAY=:"+strconv.Itoa(initData.Display)) } return &initState{ log: log, config: &initData.Config, sockaddr: initData.Sockaddr, launchEnv: env, profile: &initData.Profile, children: make(map[int]*exec.Cmd), uid: initData.Uid, gid: initData.Gid, gids: initData.Gids, user: &initData.User, display: initData.Display, fs: fs.NewFilesystem(&initData.Config, log), network: &initData.Network, } }
func (st *initState) setupFilesystem(extra []oz.WhitelistItem) error { fs := fs.NewFilesystem(st.config, st.log) if err := setupRootfs(fs, st.uid, st.gid, st.config.UseFullDev); err != nil { return err } if err := st.bindWhitelist(fs, st.profile.Whitelist); err != nil { return err } if err := st.bindWhitelist(fs, extra); err != nil { return err } if err := st.applyBlacklist(fs, st.profile.Blacklist); err != nil { return err } if st.profile.XServer.Enabled { xprapath, err := xpra.CreateDir(st.user, st.profile.Name) if err != nil { return err } if err := fs.BindPath(xprapath, 0, nil); err != nil { return err } } if err := fs.Chroot(); err != nil { return err } mo := &mountOps{} if st.config.UseFullDev { mo.add(fs.MountFullDev) } mo.add(fs.MountShm /*fs.MountTmp, */, fs.MountPts) if !st.profile.NoSysProc { mo.add(fs.MountProc, fs.MountSys) } return mo.run() }
func Main(mode int) { log := createLogger() config, err := loadConfig() if err != nil { log.Error("Could not load configuration: %s (%+v)", oz.DefaultConfigPath, err) os.Exit(1) } fsys := fs.NewFilesystem(config, log) homedir := os.Getenv("_OZ_HOMEDIR") if homedir == "" { log.Error("Homedir must be set!") os.Exit(1) } os.Setenv("_OZ_HOMEDIR", "") start := 1 readonly := false if os.Args[1] == "--readonly" { start = 2 readonly = true } for _, fpath := range os.Args[start:] { cpath, err := cleanPath(fpath, homedir) if err != nil || cpath == "" { log.Error("%v", err) os.Exit(1) } switch mode { case MOUNT: mount(cpath, readonly, fsys, log) case UMOUNT: unmount(cpath, fsys, log) default: log.Error("Unknown mode!") os.Exit(1) } } os.Exit(0) }
func parseArgs() *initState { log := createLogger() if os.Getuid() != 0 { log.Error("oz-init must run as root\n") os.Exit(1) } if os.Getpid() != 1 { log.Error("oz-init must be launched in new pid namespace.") os.Exit(1) } getvar := func(name string) string { val := os.Getenv(name) if val == "" { log.Error("Error: missing required '%s' argument", name) os.Exit(1) } return val } pname := getvar("INIT_PROFILE") sockaddr := getvar("INIT_SOCKET") uidval := getvar("INIT_UID") dispval := os.Getenv("INIT_DISPLAY") stnip := os.Getenv("INIT_ADDR") stnvhost := os.Getenv("INIT_VHOST") stnvguest := os.Getenv("INIT_VGUEST") stngateway := os.Getenv("INIT_GATEWAY") var config *oz.Config config, err := oz.LoadConfig(oz.DefaultConfigPath) if err != nil { if os.IsNotExist(err) { log.Info("Configuration file (%s) is missing, using defaults.", oz.DefaultConfigPath) config = oz.NewDefaultConfig() } else { log.Error("Could not load configuration: %s", oz.DefaultConfigPath, err) os.Exit(1) } } p, err := loadProfile(config.ProfileDir, pname) if err != nil { log.Error("Could not load profile %s: %v", pname, err) os.Exit(1) } uid, err := strconv.Atoi(uidval) if err != nil { log.Error("Could not parse INIT_UID argument (%s) into an integer: %v", uidval, err) os.Exit(1) } u, err := user.LookupId(uidval) if err != nil { log.Error("Failed to look up user with uid=%s: %v", uidval, err) os.Exit(1) } gid, err := strconv.Atoi(u.Gid) if err != nil { log.Error("Failed to parse gid value (%s) from user struct: %v", u.Gid, err) os.Exit(1) } display := 0 if dispval != "" { d, err := strconv.Atoi(dispval) if err != nil { log.Error("Unable to parse display (%s) into an integer: %v", dispval, err) os.Exit(1) } display = d } stn := new(network.SandboxNetwork) if stnip != "" { gateway, _, err := net.ParseCIDR(stngateway) if err != nil { log.Error("Unable to parse network configuration gateway (%s): %v", stngateway, err) os.Exit(1) } stn.Ip = stnip stn.VethHost = stnvhost stn.VethGuest = stnvguest stn.Gateway = gateway } env := []string{} for _, e := range os.Environ() { if strings.HasPrefix(e, EnvPrefix) { e = e[len(EnvPrefix):] log.Debug("Adding (%s) to launch environment", e) env = append(env, e) } } env = append(env, "PATH=/usr/bin:/bin") if p.XServer.Enabled { env = append(env, "DISPLAY=:"+strconv.Itoa(display)) } return &initState{ log: log, config: config, sockaddr: sockaddr, launchEnv: env, profile: p, children: make(map[int]*exec.Cmd), uid: uid, gid: gid, user: u, display: display, fs: fs.NewFilesystem(config, log), network: stn, } }
func (d *daemonState) launch(p *oz.Profile, msg *LaunchMsg, rawEnv []string, uid, gid uint32, log *logging.Logger) (*Sandbox, error) { /* u, err := user.LookupId(fmt.Sprintf("%d", uid)) if err != nil { return nil, fmt.Errorf("failed to lookup user for uid=%d: %v", uid, err) } fs := fs.NewFromProfile(p, u, d.config.SandboxPath, d.config.UseFullDev, d.log) if err := fs.Setup(d.config.ProfileDir); err != nil { return nil, err } */ u, err := user.LookupId(strconv.FormatUint(uint64(uid), 10)) if err != nil { return nil, fmt.Errorf("Failed to look up user with uid=%ld: %v", uid, err) } groups, err := d.sanitizeGroups(p, u.Username, msg.Gids) if err != nil { return nil, fmt.Errorf("Unable to sanitize user groups: %v", err) } display := 0 if p.XServer.Enabled && p.Networking.Nettype == network.TYPE_HOST { display = d.nextDisplay d.nextDisplay += 1 } stn := new(network.SandboxNetwork) stn.Nettype = p.Networking.Nettype if p.Networking.Nettype == network.TYPE_BRIDGE { stn, err = network.PrepareSandboxNetwork(nil, d.network, log) if err != nil { return nil, fmt.Errorf("Unable to prepare veth network: %+v", err) } if err := network.NetInit(stn, d.network, log); err != nil { return nil, fmt.Errorf("Unable to create veth networking: %+v", err) } } socketPath, err := createSocketPath(path.Join(d.config.SandboxPath, "sockets")) if err != nil { return nil, fmt.Errorf("Failed to create random socket path: %v", err) } initPath := path.Join(d.config.PrefixPath, "bin", "oz-init") cmd := createInitCommand(initPath, (stn.Nettype != network.TYPE_HOST)) pp, err := cmd.StderrPipe() if err != nil { //fs.Cleanup() return nil, fmt.Errorf("error creating stderr pipe for init process: %v", err) } pi, err := cmd.StdinPipe() if err != nil { //fs.Cleanup() return nil, fmt.Errorf("error creating stdin pipe for init process: %v", err) } jdata, err := json.Marshal(ozinit.InitData{ Display: display, User: *u, Uid: uid, Gid: gid, Gids: groups, Network: network.SandboxNetwork{ Interface: stn.Interface, VethHost: stn.VethHost, VethGuest: stn.VethGuest, Ip: stn.Ip, Gateway: stn.Gateway, Class: stn.Class, Nettype: stn.Nettype, }, Profile: *p, Config: *d.config, Sockaddr: socketPath, LaunchEnv: msg.Env, }) if err != nil { return nil, fmt.Errorf("Unable to marshal init state: %+v", err) } io.Copy(pi, bytes.NewBuffer(jdata)) pi.Close() if err := cmd.Start(); err != nil { //fs.Cleanup() return nil, fmt.Errorf("Unable to start process: %+v", err) } //rootfs := path.Join(d.config.SandboxPath, "rootfs") sbox := &Sandbox{ daemon: d, id: d.nextSboxId, display: display, profile: p, init: cmd, cred: &syscall.Credential{Uid: uid, Gid: gid, Groups: msg.Gids}, user: u, fs: fs.NewFilesystem(d.config, log), //addr: path.Join(rootfs, ozinit.SocketAddress), addr: socketPath, stderr: pp, network: stn, rawEnv: rawEnv, } sbox.ready.Add(1) sbox.waiting.Add(1) go sbox.logMessages() sbox.waiting.Wait() if p.Networking.Nettype == network.TYPE_BRIDGE { if err := network.NetAttach(stn, d.network, cmd.Process.Pid); err != nil { cmd.Process.Kill() return nil, fmt.Errorf("Unable to attach veth networking: %+v", err) } } cmd.Process.Signal(syscall.SIGUSR1) wgNet := new(sync.WaitGroup) if p.Networking.Nettype != network.TYPE_HOST && p.Networking.Nettype != network.TYPE_NONE && len(p.Networking.Sockets) > 0 { wgNet.Add(1) go func() { defer wgNet.Done() sbox.ready.Wait() err := network.ProxySetup(sbox.init.Process.Pid, p.Networking.Sockets, d.log, sbox.ready) if err != nil { log.Warning("Unable to create connection proxy: %+s", err) } }() } if !msg.Noexec { go func() { sbox.ready.Wait() wgNet.Wait() go sbox.launchProgram(d.config.PrefixPath, msg.Path, msg.Pwd, msg.Args, log) }() } if sbox.profile.XServer.Enabled { go func() { sbox.ready.Wait() go sbox.startXpraClient() }() } d.nextSboxId += 1 d.sandboxes = append(d.sandboxes, sbox) return sbox, nil }