Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'internal/jail/jail.go')
-rw-r--r--internal/jail/jail.go55
1 files changed, 54 insertions, 1 deletions
diff --git a/internal/jail/jail.go b/internal/jail/jail.go
index 16690235..d2b04be0 100644
--- a/internal/jail/jail.go
+++ b/internal/jail/jail.go
@@ -5,12 +5,18 @@ import (
"io"
"os"
"path"
+ "syscall"
"time"
+
+ "golang.org/x/sys/unix"
)
type pathAndMode struct {
path string
mode os.FileMode
+
+ // Only respected if mode is os.ModeCharDevice
+ rdev int
}
// Jail is a Chroot jail builder
@@ -64,7 +70,7 @@ func (j *Jail) Build() error {
}
for dest, src := range j.files {
- if err := copyFile(dest, src.path, src.mode); err != nil {
+ if err := handleFile(dest, src); err != nil {
j.removeAll()
return fmt.Errorf("Can't copy %q -> %q. %s", src.path, dest, err)
}
@@ -102,6 +108,34 @@ func (j *Jail) MkDir(path string, perm os.FileMode) {
j.directories = append(j.directories, pathAndMode{path: j.ExternalPath(path), mode: perm})
}
+// CharDev enqueues an mknod operation for the given character device at jail
+// building time
+func (j *Jail) CharDev(path string) error {
+ fi, err := os.Stat(path)
+ if err != nil {
+ return fmt.Errorf("Can't stat %q: %s", path, err)
+ }
+
+ if (fi.Mode() & os.ModeCharDevice) == 0 {
+ return fmt.Errorf("Can't mknod %q: not a character device", path)
+ }
+
+ // Read the device number from the underlying unix implementation of stat()
+ sys, ok := fi.Sys().(*syscall.Stat_t)
+ if !ok {
+ return fmt.Errorf("Couldn't determine rdev for %q", path)
+ }
+
+ jailedDest := j.ExternalPath(path)
+ j.files[jailedDest] = pathAndMode{
+ path: path,
+ mode: fi.Mode(),
+ rdev: int(sys.Rdev),
+ }
+
+ return nil
+}
+
// CopyTo enqueues a file copy operation at jail building time
func (j *Jail) CopyTo(dest, src string) error {
fi, err := os.Stat(src)
@@ -143,6 +177,25 @@ func (j *Jail) ExternalPath(internal string) string {
return path.Join(j.Path(), internal)
}
+func handleFile(dest string, src pathAndMode) error {
+ // Using `io.Copy` on a character device simply doesn't work
+ if (src.mode & os.ModeCharDevice) > 0 {
+ return createCharacterDevice(dest, src)
+ }
+
+ // FIXME: currently, symlinks, block devices, named pipes and other
+ // non-regular files will be `Open`ed and have that content streamed to a
+ // regular file inside the chroot. This is actually desired behaviour for,
+ // e.g., `/etc/resolv.conf`, but was very surprising
+ return copyFile(dest, src.path, src.mode)
+}
+
+func createCharacterDevice(dest string, src pathAndMode) error {
+ unixMode := uint32(src.mode.Perm() | syscall.S_IFCHR)
+
+ return unix.Mknod(dest, unixMode, src.rdev)
+}
+
func copyFile(dest, src string, perm os.FileMode) error {
srcFile, err := os.Open(src)
if err != nil {