예제 #1
0
파일: init.go 프로젝트: drptbl/oz
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,
	}
}
예제 #2
0
파일: launch.go 프로젝트: Safe3/oz
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
}