// Copyright © 2020 Ettore Di Giacinto // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License along // with this program; if not, see . package box import ( "os" "path/filepath" "syscall" ) func PivotRoot(newroot string) error { putold := filepath.Join(newroot, "/.pivot_root") // bind mount newroot to itself - this is a slight hack needed to satisfy the // pivot_root requirement that newroot and putold must not be on the same // filesystem as the current root if err := syscall.Mount(newroot, newroot, "", syscall.MS_BIND|syscall.MS_REC, ""); err != nil { return err } // create putold directory if err := os.MkdirAll(putold, 0700); err != nil { return err } // call pivot_root if err := syscall.PivotRoot(newroot, putold); err != nil { return err } // ensure current working directory is set to new root if err := os.Chdir("/"); err != nil { return err } // umount putold, which now lives at /.pivot_root putold = "/.pivot_root" if err := syscall.Unmount(putold, syscall.MNT_DETACH); err != nil { return err } // remove putold if err := os.RemoveAll(putold); err != nil { return err } return nil } func mountProc(newroot string) error { source := "proc" target := filepath.Join(newroot, "/proc") fstype := "proc" flags := 0 data := "" os.MkdirAll(target, 0755) if err := syscall.Mount(source, target, fstype, uintptr(flags), data); err != nil { return err } return nil } func mountBind(hostfolder, newroot, dst string) error { source := hostfolder target := filepath.Join(newroot, dst) fstype := "bind" data := "" os.MkdirAll(target, 0755) if err := syscall.Mount(source, target, fstype, syscall.MS_BIND|syscall.MS_REC, data); err != nil { return err } return nil } func mountDev(newroot string) error { return mountBind("/dev", newroot, "/dev") }