PageRenderTime 328ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/oz-init/init.go

https://gitlab.com/Lin0x/oz
Go | 823 lines | 707 code | 91 blank | 25 comment | 226 complexity | 53a34b4c0d82306f3f912764f6b466bc MD5 | raw file
  1. package ozinit
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "os"
  10. "os/exec"
  11. "os/signal"
  12. "os/user"
  13. "path"
  14. "path/filepath"
  15. "regexp"
  16. "strconv"
  17. "strings"
  18. "sync"
  19. "syscall"
  20. //"time"
  21. "github.com/subgraph/oz"
  22. "github.com/subgraph/oz/fs"
  23. "github.com/subgraph/oz/ipc"
  24. "github.com/subgraph/oz/network"
  25. "github.com/subgraph/oz/xpra"
  26. "github.com/kr/pty"
  27. "github.com/op/go-logging"
  28. )
  29. type procState struct {
  30. cmd *exec.Cmd
  31. track bool
  32. }
  33. type initState struct {
  34. log *logging.Logger
  35. profile *oz.Profile
  36. config *oz.Config
  37. sockaddr string
  38. launchEnv []string
  39. lock sync.Mutex
  40. children map[int]procState
  41. uid uint32
  42. gid uint32
  43. gids map[string]uint32
  44. user *user.User
  45. display int
  46. fs *fs.Filesystem
  47. ipcServer *ipc.MsgServer
  48. xpra *xpra.Xpra
  49. xpraReady sync.WaitGroup
  50. network *network.SandboxNetwork
  51. dbusUuid string
  52. shutdownRequested bool
  53. }
  54. type InitData struct {
  55. Profile oz.Profile
  56. Config oz.Config
  57. Sockaddr string
  58. LaunchEnv []string
  59. Uid uint32
  60. Gid uint32
  61. Gids map[string]uint32
  62. User user.User
  63. Network network.SandboxNetwork
  64. Display int
  65. }
  66. const (
  67. DBUS_VAR_REGEXP = "[A-Za-z_]+=[a-zA-Z_:-@]+=/tmp/.+"
  68. )
  69. var dbusValidVar = regexp.MustCompile(DBUS_VAR_REGEXP)
  70. // By convention oz-init writes log messages to stderr with a single character
  71. // prefix indicating the logging level. These messages are read one line at a time
  72. // over a pipe by oz-daemon and translated into appropriate log events.
  73. func createLogger() *logging.Logger {
  74. l := logging.MustGetLogger("oz-init")
  75. be := logging.NewLogBackend(os.Stderr, "", 0)
  76. f := logging.MustStringFormatter("%{level:.1s} %{message}")
  77. fbe := logging.NewBackendFormatter(be, f)
  78. logging.SetBackend(fbe)
  79. return l
  80. }
  81. func Main() {
  82. parseArgs().waitForParentReady().runInit()
  83. }
  84. func parseArgs() *initState {
  85. log := createLogger()
  86. if os.Getuid() != 0 {
  87. log.Error("oz-init must run as root\n")
  88. os.Exit(1)
  89. }
  90. if os.Getpid() != 1 {
  91. log.Error("oz-init must be launched in new pid namespace.")
  92. os.Exit(1)
  93. }
  94. initData := new(InitData)
  95. if err := json.NewDecoder(os.Stdin).Decode(&initData); err != nil {
  96. log.Error("unable to decode init data: %v", err)
  97. os.Exit(1)
  98. }
  99. log.Debug("Init state: %+v", initData)
  100. if (initData.User.Uid != strconv.Itoa(int(initData.Uid))) || (initData.Uid == 0) {
  101. log.Error("invalid uid or user passed to init.")
  102. os.Exit(1)
  103. }
  104. env := []string{}
  105. env = append(env, initData.LaunchEnv...)
  106. env = append(env, "PATH=/usr/bin:/bin")
  107. if initData.Profile.XServer.Enabled {
  108. env = append(env, "DISPLAY=:"+strconv.Itoa(initData.Display))
  109. }
  110. return &initState{
  111. log: log,
  112. config: &initData.Config,
  113. sockaddr: initData.Sockaddr,
  114. launchEnv: env,
  115. profile: &initData.Profile,
  116. children: make(map[int]procState),
  117. uid: initData.Uid,
  118. gid: initData.Gid,
  119. gids: initData.Gids,
  120. user: &initData.User,
  121. display: initData.Display,
  122. fs: fs.NewFilesystem(&initData.Config, log),
  123. network: &initData.Network,
  124. }
  125. }
  126. func (st *initState) waitForParentReady() *initState {
  127. // Signal the daemon we are ready
  128. os.Stderr.WriteString("WAITING\n")
  129. c := make(chan os.Signal)
  130. signal.Notify(c, syscall.SIGUSR1)
  131. sig := <-c
  132. st.log.Info("Recieved SIGUSR1 from parent (%v), ready to init.", sig)
  133. signal.Stop(c)
  134. return st
  135. }
  136. func (st *initState) runInit() {
  137. st.log.Info("Starting oz-init for profile: %s", st.profile.Name)
  138. sigs := make(chan os.Signal)
  139. signal.Notify(sigs, syscall.SIGTERM, os.Interrupt)
  140. s, err := ipc.NewServer(st.sockaddr, messageFactory, st.log,
  141. handlePing,
  142. st.handleRunProgram,
  143. st.handleRunShell,
  144. )
  145. if err != nil {
  146. st.log.Error("NewServer failed: %v", err)
  147. os.Exit(1)
  148. }
  149. if err := os.Chown(st.sockaddr, int(st.uid), int(st.gid)); err != nil {
  150. st.log.Warning("Failed to chown oz-init control socket: %v", err)
  151. }
  152. wlExtras := []oz.WhitelistItem{}
  153. blExtras := []oz.BlacklistItem{}
  154. //wlExtras = append(wlExtras, oz.WhitelistItem{Path: "/etc/oz/mimeapps.list", Target: "${HOME}/.config/mimeapps.list", ReadOnly: true})
  155. //wlExtras = append(wlExtras, oz.WhitelistItem{Path: "/etc/oz/mimeapps.list", Target: "/etc/gnome/defaults.list", Force: true, ReadOnly: true})
  156. //blExtras = append(blExtras, oz.BlacklistItem{Path: "/etc/shadow"})
  157. //blExtras = append(blExtras, oz.BlacklistItem{Path: "/etc/shadow-"})
  158. if st.profile.XServer.AudioMode == oz.PROFILE_AUDIO_PULSE {
  159. wlExtras = append(wlExtras, oz.WhitelistItem{Path: "/run/user/${UID}/pulse/native", Ignore: true})
  160. wlExtras = append(wlExtras, oz.WhitelistItem{Path: "${HOME}/.config/pulse/cookie", Ignore: true, ReadOnly: true})
  161. wlExtras = append(wlExtras, oz.WhitelistItem{Path: "/dev/shm/pulse-shm-*", Ignore: true})
  162. }
  163. if err := st.setupFilesystem(wlExtras, blExtras); err != nil {
  164. st.log.Error("Failed to setup filesytem: %v", err)
  165. os.Exit(1)
  166. }
  167. if st.user != nil && st.user.HomeDir != "" {
  168. st.launchEnv = append(st.launchEnv, "HOME="+st.user.HomeDir)
  169. }
  170. if st.profile.Networking.Nettype != network.TYPE_HOST ||
  171. st.profile.Networking.Nettype != network.TYPE_NONE {
  172. err := network.NetSetup(st.network)
  173. if err != nil {
  174. st.log.Error("Unable to setup networking: %+v", err)
  175. os.Exit(1)
  176. }
  177. }
  178. network.NetPrint(st.log)
  179. if syscall.Sethostname([]byte(st.profile.Name)) != nil {
  180. st.log.Error("Failed to set hostname to (%s)", st.profile.Name)
  181. os.Exit(1)
  182. }
  183. if syscall.Setdomainname([]byte("local")) != nil {
  184. st.log.Error("Failed to set domainname")
  185. }
  186. st.log.Info("Hostname set to (%s.local)", st.profile.Name)
  187. if err := st.setupDbus(); err != nil {
  188. st.log.Error("Unable to setup dbus: %v", err)
  189. os.Exit(1)
  190. }
  191. oz.ReapChildProcs(st.log, st.handleChildExit)
  192. if st.profile.XServer.Enabled {
  193. st.xpraReady.Add(1)
  194. st.startXpraServer()
  195. st.xpraReady.Wait()
  196. st.log.Info("XPRA started")
  197. }
  198. if st.needsDbus() {
  199. if err := st.getDbusSession(); err != nil {
  200. st.log.Error("Unable to get dbus session information: %v", err)
  201. os.Exit(1)
  202. }
  203. }
  204. fsbx := path.Join("/tmp", "oz-sandbox")
  205. err = ioutil.WriteFile(fsbx, []byte(st.profile.Name), 0644)
  206. // Signal the daemon we are ready
  207. os.Stderr.WriteString("OK\n")
  208. go st.processSignals(sigs, s)
  209. st.ipcServer = s
  210. if err := s.Run(); err != nil {
  211. st.log.Warning("MsgServer.Run() return err: %v", err)
  212. }
  213. st.log.Info("oz-init exiting...")
  214. }
  215. func (st *initState) needsDbus() bool {
  216. return (st.profile.XServer.AudioMode == oz.PROFILE_AUDIO_FULL ||
  217. st.profile.XServer.AudioMode == oz.PROFILE_AUDIO_SPEAKER ||
  218. st.profile.XServer.EnableNotifications == true)
  219. }
  220. func (st *initState) setupDbus() error {
  221. exec.Command("/usr/bin/dbus-uuidgen", "--ensure").Run()
  222. buuid, err := exec.Command("/usr/bin/dbus-uuidgen", "--get").CombinedOutput()
  223. if err != nil || string(buuid) == "" {
  224. return fmt.Errorf("dbus-uuidgen failed: %v %v", err, string(buuid))
  225. }
  226. st.dbusUuid = strings.TrimSpace(string(bytes.Trim(buuid, "\x00")))
  227. st.log.Debug("dbus-uuid: %s", st.dbusUuid)
  228. return nil
  229. }
  230. func (st *initState) getDbusSession() error {
  231. args := []string{
  232. "--autolaunch",
  233. st.dbusUuid,
  234. "--sh-syntax",
  235. "--close-stderr",
  236. }
  237. dcmd := exec.Command("/usr/bin/dbus-launch", args...)
  238. dcmd.Env = append([]string{}, st.launchEnv...)
  239. //st.log.Debug("%s /usr/bin/dbus-launch %s", strings.Join(dcmd.Env, " "), strings.Join(args, " "))
  240. dcmd.SysProcAttr = &syscall.SysProcAttr{}
  241. dcmd.SysProcAttr.Credential = &syscall.Credential{
  242. Uid: st.uid,
  243. Gid: st.gid,
  244. }
  245. benvs, err := dcmd.Output()
  246. if err != nil && len(benvs) <= 1 {
  247. return fmt.Errorf("dbus-launch failed: %v %v", err, string(benvs))
  248. }
  249. benvs = bytes.Trim(benvs, "\x00")
  250. senvs := strings.TrimSpace(string(benvs))
  251. senvs = strings.Replace(senvs, "export ", "", -1)
  252. senvs = strings.Replace(senvs, ";", "", -1)
  253. senvs = strings.Replace(senvs, "'", "", -1)
  254. dbusenv := ""
  255. for _, line := range strings.Split(senvs, "\n") {
  256. if dbusValidVar.MatchString(line) {
  257. dbusenv = line
  258. break
  259. }
  260. }
  261. if dbusenv != "" {
  262. st.launchEnv = append(st.launchEnv, dbusenv)
  263. vv := strings.Split(dbusenv, "=")
  264. os.Setenv(vv[0], strings.Join(vv[1:], "="))
  265. }
  266. return nil
  267. }
  268. func (st *initState) startXpraServer() {
  269. if st.user == nil {
  270. st.log.Warning("Cannot start xpra server because no user is set")
  271. return
  272. }
  273. workdir := path.Join(st.user.HomeDir, ".Xoz", st.profile.Name)
  274. st.log.Info("xpra work dir is %s", workdir)
  275. spath := path.Join(st.config.PrefixPath, "bin", "oz-seccomp")
  276. xpra := xpra.NewServer(&st.profile.XServer, uint64(st.display), spath, workdir)
  277. //st.log.Debug("%s %s", strings.Join(xpra.Process.Env, " "), strings.Join(xpra.Process.Args, " "))
  278. if xpra == nil {
  279. st.log.Error("Error creating xpra server command")
  280. os.Exit(1)
  281. }
  282. p, err := xpra.Process.StderrPipe()
  283. if err != nil {
  284. st.log.Error("Error creating stderr pipe for xpra output: %v", err)
  285. os.Exit(1)
  286. }
  287. go st.readXpraOutput(p)
  288. xpra.Process.Env = []string{
  289. "HOME=" + st.user.HomeDir,
  290. }
  291. groups := append([]uint32{}, st.gid)
  292. if gid, gexists := st.gids["video"]; gexists {
  293. groups = append(groups, gid)
  294. }
  295. if st.profile.XServer.AudioMode != oz.PROFILE_AUDIO_NONE {
  296. if gid, gexists := st.gids["audio"]; gexists {
  297. groups = append(groups, gid)
  298. }
  299. }
  300. xpra.Process.SysProcAttr = &syscall.SysProcAttr{}
  301. xpra.Process.SysProcAttr.Credential = &syscall.Credential{
  302. Uid: st.uid,
  303. Gid: st.gid,
  304. Groups: groups,
  305. }
  306. st.log.Info("Starting xpra server")
  307. if err := xpra.Process.Start(); err != nil {
  308. st.log.Warning("Failed to start xpra server: %v", err)
  309. st.xpraReady.Done()
  310. }
  311. st.xpra = xpra
  312. }
  313. func (st *initState) readXpraOutput(r io.ReadCloser) {
  314. sc := bufio.NewScanner(r)
  315. seenReady := false
  316. for sc.Scan() {
  317. line := sc.Text()
  318. if len(line) > 0 {
  319. //if strings.Contains(line, "_OZ_XXSTARTEDXX") &&
  320. // strings.Contains(line, "has terminated") && !seenReady {
  321. if strings.Contains(line, "xpra is ready.") && !seenReady {
  322. seenReady = true
  323. st.xpraReady.Done()
  324. if !st.config.LogXpra {
  325. r.Close()
  326. return
  327. }
  328. }
  329. if st.config.LogXpra {
  330. st.log.Debug("(xpra-server) %s", line)
  331. }
  332. }
  333. }
  334. }
  335. func (st *initState) launchApplication(cpath, pwd string, cmdArgs []string) (*exec.Cmd, error) {
  336. if cpath == "" {
  337. cpath = st.profile.Path
  338. }
  339. if st.config.DivertSuffix != "" {
  340. cpath += "." + st.config.DivertSuffix
  341. }
  342. if st.config.DivertPath {
  343. cpath = path.Join(path.Dir(cpath)+"-oz", path.Base(cpath))
  344. }
  345. if len(st.profile.DefaultParams) > 0 {
  346. cmdArgs = append(st.profile.DefaultParams, cmdArgs...)
  347. }
  348. switch st.profile.Seccomp.Mode {
  349. case oz.PROFILE_SECCOMP_TRAIN:
  350. st.log.Notice("Enabling seccomp training mode for : %s", cpath)
  351. spath := path.Join(st.config.PrefixPath, "bin", "oz-seccomp")
  352. cmdArgs = append([]string{spath, "-mode=whitelist", cpath}, cmdArgs...)
  353. cpath = path.Join(st.config.PrefixPath, "bin", "oz-seccomp-tracer")
  354. case oz.PROFILE_SECCOMP_WHITELIST:
  355. st.log.Notice("Enabling seccomp whitelist for: %s", cpath)
  356. if st.profile.Seccomp.Enforce == false {
  357. spath := path.Join(st.config.PrefixPath, "bin", "oz-seccomp")
  358. cmdArgs = append([]string{spath, "-mode=whitelist", cpath}, cmdArgs...)
  359. cpath = path.Join(st.config.PrefixPath, "bin", "oz-seccomp-tracer")
  360. } else {
  361. cmdArgs = append([]string{"-mode=whitelist", cpath}, cmdArgs...)
  362. cpath = path.Join(st.config.PrefixPath, "bin", "oz-seccomp")
  363. }
  364. case oz.PROFILE_SECCOMP_BLACKLIST:
  365. st.log.Notice("Enabling seccomp blacklist for: %s", cpath)
  366. if st.profile.Seccomp.Enforce == false {
  367. spath := path.Join(st.config.PrefixPath, "bin", "oz-seccomp")
  368. cmdArgs = append([]string{spath, "-mode=blacklist", cpath}, cmdArgs...)
  369. cpath = path.Join(st.config.PrefixPath, "bin", "oz-seccomp-tracer")
  370. } else {
  371. cmdArgs = append([]string{"-mode=blacklist", cpath}, cmdArgs...)
  372. cpath = path.Join(st.config.PrefixPath, "bin", "oz-seccomp")
  373. }
  374. }
  375. cmd := exec.Command(cpath)
  376. stdout, err := cmd.StdoutPipe()
  377. if err != nil {
  378. st.log.Warning("Failed to create stdout pipe: %v", err)
  379. return nil, err
  380. }
  381. stderr, err := cmd.StderrPipe()
  382. if err != nil {
  383. st.log.Warning("Failed to create stderr pipe: %v", err)
  384. return nil, err
  385. }
  386. groups := append([]uint32{}, st.gid)
  387. for _, gid := range st.gids {
  388. groups = append(groups, gid)
  389. }
  390. cmd.SysProcAttr = &syscall.SysProcAttr{}
  391. cmd.SysProcAttr.Credential = &syscall.Credential{
  392. Uid: st.uid,
  393. Gid: st.gid,
  394. Groups: groups,
  395. }
  396. cmd.Env = append(cmd.Env, st.launchEnv...)
  397. if st.profile.Seccomp.Mode == oz.PROFILE_SECCOMP_WHITELIST ||
  398. st.profile.Seccomp.Mode == oz.PROFILE_SECCOMP_BLACKLIST || st.profile.Seccomp.Mode == oz.PROFILE_SECCOMP_TRAIN {
  399. pi, err := cmd.StdinPipe()
  400. if err != nil {
  401. return nil, fmt.Errorf("error creating stdin pipe for seccomp process: %v", err)
  402. }
  403. jdata, err := json.Marshal(st.profile)
  404. if err != nil {
  405. return nil, fmt.Errorf("Unable to marshal seccomp state: %+v", err)
  406. }
  407. io.Copy(pi, bytes.NewBuffer(jdata))
  408. pi.Close()
  409. }
  410. cmd.Args = append(cmd.Args, cmdArgs...)
  411. if pwd == "" {
  412. pwd = st.user.HomeDir
  413. }
  414. if _, err := os.Stat(pwd); err == nil {
  415. cmd.Dir = pwd
  416. }
  417. if err := cmd.Start(); err != nil {
  418. st.log.Warning("Failed to start application (%s): %v", st.profile.Path, err)
  419. return nil, err
  420. }
  421. st.addChildProcess(cmd, true)
  422. go st.readApplicationOutput(stdout, "stdout")
  423. go st.readApplicationOutput(stderr, "stderr")
  424. return cmd, nil
  425. }
  426. func (st *initState) readApplicationOutput(r io.ReadCloser, label string) {
  427. sc := bufio.NewScanner(r)
  428. for sc.Scan() {
  429. line := sc.Text()
  430. st.log.Debug("(%s) %s", label, line)
  431. }
  432. }
  433. func loadProfile(dir, name string) (*oz.Profile, error) {
  434. ps, err := oz.LoadProfiles(dir)
  435. if err != nil {
  436. return nil, err
  437. }
  438. for _, p := range ps {
  439. if name == p.Name {
  440. return p, nil
  441. }
  442. }
  443. return nil, fmt.Errorf("no profile named '%s'", name)
  444. }
  445. func handlePing(ping *PingMsg, msg *ipc.Message) error {
  446. return msg.Respond(&PingMsg{Data: ping.Data})
  447. }
  448. func (st *initState) handleRunProgram(rp *RunProgramMsg, msg *ipc.Message) error {
  449. st.log.Info("Run program message received: %+v", rp)
  450. _, err := st.launchApplication(rp.Path, rp.Pwd, rp.Args)
  451. if err != nil {
  452. err := msg.Respond(&ErrorMsg{Msg: err.Error()})
  453. return err
  454. } else {
  455. err := msg.Respond(&OkMsg{})
  456. return err
  457. }
  458. }
  459. func (st *initState) handleRunShell(rs *RunShellMsg, msg *ipc.Message) error {
  460. if msg.Ucred == nil {
  461. return msg.Respond(&ErrorMsg{"No credentials received for RunShell command"})
  462. }
  463. if (msg.Ucred.Uid == 0 || msg.Ucred.Gid == 0) && st.config.AllowRootShell != true {
  464. return msg.Respond(&ErrorMsg{"Cannot open shell because allowRootShell is disabled"})
  465. }
  466. groups := append([]uint32{}, st.gid)
  467. if msg.Ucred.Uid != 0 && msg.Ucred.Gid != 0 {
  468. for _, gid := range st.gids {
  469. groups = append(groups, gid)
  470. }
  471. }
  472. st.log.Info("Starting shell with uid = %d, gid = %d", msg.Ucred.Uid, msg.Ucred.Gid)
  473. cmd := exec.Command(st.config.ShellPath, "-i")
  474. cmd.SysProcAttr = &syscall.SysProcAttr{}
  475. cmd.SysProcAttr.Credential = &syscall.Credential{
  476. Uid: msg.Ucred.Uid,
  477. Gid: msg.Ucred.Gid,
  478. Groups: groups,
  479. }
  480. cmd.Env = append(cmd.Env, st.launchEnv...)
  481. if rs.Term != "" {
  482. cmd.Env = append(cmd.Env, "TERM="+rs.Term)
  483. }
  484. if msg.Ucred.Uid != 0 && msg.Ucred.Gid != 0 {
  485. if st.user != nil && st.user.HomeDir != "" {
  486. cmd.Dir = st.user.HomeDir
  487. }
  488. }
  489. cmd.Env = append(cmd.Env, fmt.Sprintf("PS1=[%s] $ ", st.profile.Name))
  490. st.log.Info("Executing shell...")
  491. f, err := ptyStart(cmd)
  492. defer f.Close()
  493. if err != nil {
  494. return msg.Respond(&ErrorMsg{err.Error()})
  495. }
  496. st.addChildProcess(cmd, false)
  497. err = msg.Respond(&OkMsg{}, int(f.Fd()))
  498. return err
  499. }
  500. func ptyStart(c *exec.Cmd) (ptty *os.File, err error) {
  501. ptty, tty, err := pty.Open()
  502. if err != nil {
  503. return nil, err
  504. }
  505. defer tty.Close()
  506. c.Stdin = tty
  507. c.Stdout = tty
  508. c.Stderr = tty
  509. if c.SysProcAttr == nil {
  510. c.SysProcAttr = &syscall.SysProcAttr{}
  511. }
  512. c.SysProcAttr.Setctty = true
  513. c.SysProcAttr.Setsid = true
  514. if err := c.Start(); err != nil {
  515. ptty.Close()
  516. return nil, err
  517. }
  518. return ptty, nil
  519. }
  520. func (st *initState) addChildProcess(cmd *exec.Cmd, track bool) {
  521. st.lock.Lock()
  522. defer st.lock.Unlock()
  523. st.children[cmd.Process.Pid] = procState{cmd: cmd, track: track}
  524. }
  525. func (st *initState) removeChildProcess(pid int) bool {
  526. st.lock.Lock()
  527. defer st.lock.Unlock()
  528. if _, ok := st.children[pid]; ok {
  529. delete(st.children, pid)
  530. return true
  531. }
  532. return false
  533. }
  534. func (st *initState) handleChildExit(pid int, wstatus syscall.WaitStatus) {
  535. st.log.Debug("Child process pid=%d exited from init with status %d", pid, wstatus.ExitStatus())
  536. track := st.children[pid].track
  537. st.removeChildProcess(pid)
  538. for _, proc := range st.children {
  539. if proc.track {
  540. return
  541. }
  542. }
  543. if len(st.profile.Watchdog) > 0 {
  544. //if st.getProcessExists(st.profile.Watchdog) {
  545. // return
  546. //} else {
  547. // var ww sync.WaitGroup
  548. // ww.Add(1)
  549. // time.AfterFunc(time.Second*5, func() {
  550. // ww.Done()
  551. // st.log.Info("Watchdog timeout expired")
  552. // })
  553. // ww.Wait()
  554. track = !st.getProcessExists(st.profile.Watchdog)
  555. //}
  556. }
  557. if track == true && st.profile.AutoShutdown == oz.PROFILE_SHUTDOWN_YES {
  558. st.log.Info("Shutting down sandbox after child exit.")
  559. st.shutdown()
  560. }
  561. }
  562. func (st *initState) getProcessExists(pnames []string) bool {
  563. paths, _ := filepath.Glob("/proc/[0-9]*/cmdline")
  564. for _, path := range paths {
  565. pr, err := ioutil.ReadFile(path)
  566. if err != nil {
  567. continue
  568. }
  569. prs := []byte{}
  570. for _, prb := range pr {
  571. if prb == 0x00 {
  572. break
  573. }
  574. prs = append(prs, prb)
  575. }
  576. cmdb := filepath.Base(string(prs))
  577. if cmdb == "." {
  578. continue
  579. }
  580. for _, pname := range pnames {
  581. if pname == cmdb {
  582. return true
  583. }
  584. }
  585. }
  586. return false
  587. }
  588. func (st *initState) processSignals(c <-chan os.Signal, s *ipc.MsgServer) {
  589. for {
  590. sig := <-c
  591. st.log.Info("Recieved signal (%v)", sig)
  592. st.shutdown()
  593. }
  594. }
  595. func (st *initState) shutdown() {
  596. if st.shutdownRequested {
  597. return
  598. }
  599. st.shutdownRequested = true
  600. for _, c := range st.childrenVector() {
  601. c.cmd.Process.Signal(os.Interrupt)
  602. }
  603. st.shutdownXpra()
  604. if st.ipcServer != nil {
  605. st.ipcServer.Close()
  606. }
  607. }
  608. func (st *initState) shutdownXpra() {
  609. if st.xpra == nil {
  610. return
  611. }
  612. creds := &syscall.Credential{
  613. Uid: uint32(st.uid),
  614. Gid: uint32(st.gid),
  615. }
  616. out, err := st.xpra.Stop(creds)
  617. if err != nil {
  618. st.log.Warning("Error running xpra stop: %v", err)
  619. return
  620. }
  621. for _, line := range strings.Split(string(out), "\n") {
  622. if len(line) > 0 {
  623. st.log.Debug("(xpra stop) %s", line)
  624. }
  625. }
  626. }
  627. func (st *initState) childrenVector() []procState {
  628. st.lock.Lock()
  629. defer st.lock.Unlock()
  630. cs := make([]procState, 0, len(st.children))
  631. for _, v := range st.children {
  632. cs = append(cs, v)
  633. }
  634. return cs
  635. }
  636. func (st *initState) setupFilesystem(extra_whitelist []oz.WhitelistItem, extra_blacklist []oz.BlacklistItem) error {
  637. fs := fs.NewFilesystem(st.config, st.log)
  638. if err := setupRootfs(fs, st.user, st.uid, st.gid, st.display, st.config.UseFullDev, st.log); err != nil {
  639. return err
  640. }
  641. if err := st.bindWhitelist(fs, extra_whitelist); err != nil {
  642. return err
  643. }
  644. if err := st.bindWhitelist(fs, st.profile.Whitelist); err != nil {
  645. return err
  646. }
  647. if err := st.applyBlacklist(fs, extra_blacklist); err != nil {
  648. return err
  649. }
  650. if err := st.applyBlacklist(fs, st.profile.Blacklist); err != nil {
  651. return err
  652. }
  653. if st.profile.XServer.Enabled {
  654. xprapath, err := xpra.CreateDir(st.user, st.profile.Name)
  655. if err != nil {
  656. return err
  657. }
  658. if err := fs.BindPath(xprapath, 0, st.display, nil); err != nil {
  659. return err
  660. }
  661. }
  662. if err := fs.Chroot(); err != nil {
  663. return err
  664. }
  665. mo := &mountOps{}
  666. if st.config.UseFullDev {
  667. mo.add(fs.MountFullDev, fs.MountShm)
  668. }
  669. mo.add( /*fs.MountTmp, */ fs.MountPts)
  670. if !st.profile.NoSysProc {
  671. mo.add(fs.MountProc, fs.MountSys)
  672. }
  673. return mo.run()
  674. }
  675. func (st *initState) bindWhitelist(fsys *fs.Filesystem, wlist []oz.WhitelistItem) error {
  676. if wlist == nil {
  677. return nil
  678. }
  679. for _, wl := range wlist {
  680. flags := 0
  681. if wl.CanCreate {
  682. flags |= fs.BindCanCreate
  683. }
  684. if wl.Ignore {
  685. flags |= fs.BindIgnore
  686. }
  687. if wl.ReadOnly {
  688. flags |= fs.BindReadOnly
  689. }
  690. if wl.Force {
  691. flags |= fs.BindForce
  692. }
  693. if wl.NoFollow {
  694. flags |= fs.BindNoFollow
  695. }
  696. if wl.Path == "" {
  697. continue
  698. }
  699. if err := fsys.BindTo(wl.Path, wl.Target, flags, st.display, st.user); err != nil {
  700. return err
  701. }
  702. }
  703. return nil
  704. }
  705. func (st *initState) applyBlacklist(fsys *fs.Filesystem, blist []oz.BlacklistItem) error {
  706. if blist == nil {
  707. return nil
  708. }
  709. for _, bl := range blist {
  710. if bl.Path == "" {
  711. continue
  712. }
  713. if err := fsys.BlacklistPath(bl.Path, st.display, st.user); err != nil {
  714. return err
  715. }
  716. }
  717. return nil
  718. }
  719. type mountOps struct {
  720. ops []func() error
  721. }
  722. func (mo *mountOps) add(f ...func() error) {
  723. mo.ops = append(mo.ops, f...)
  724. }
  725. func (mo *mountOps) run() error {
  726. for _, f := range mo.ops {
  727. if err := f(); err != nil {
  728. return err
  729. }
  730. }
  731. return nil
  732. }