goclone

package module
v0.0.0-...-e59bcd7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 16, 2017 License: Apache-2.0 Imports: 9 Imported by: 0

README

goclone

A go library that wraps the linux 'clone' system call.

Most of this modules documentation is found in its godoc which is accessible at via the pkgdoc.org website: godoc

Primarily this package was intended to give access to linux name spaces in a usable way for golang programs.

Continuous Integration Documentation Coverage

Examples

Run command in new namespace

cmd := goclone.Command("/bin/bash")

// Set namespaces
cmd.NewIPCNameSpace = true
cmd.NewMountNameSpace = true
cmd.NewNetworkNameSpace = true
cmd.NewPIDNameSpace = true
cmd.NewUTSNameSpace = true
// Set work dir in namespace
cmd.Dir = "/"
// Set hostname
cmd.Hostname = "foo-bar.com"
// Create pseudo-devices: tty, zero, null, full, random, urandom
cmd.CreatePseudoDevices = true
// Enter to chroot
cmd.SysProcAttr = &syscall.SysProcAttr{
    Chroot: "/my_super_jail",
}
// Set uid, gid in chroot
uid, gid := 0, 0
cmd.SysProcAttr.Credential = &syscall.Credential{
    Uid: uint32(uid),
    Gid: uint32(gid),
}
// Redirect stdin, stdout, stderr
cmd.Stdin = os.Stdin
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout
// Start command
if err := cmd.Start(); err != nil {
    log.Fatalf("Failed to start command: %s", err)
}
// Get pid
pid := cmd.Process.Pid
log.Println("Command started", cmd.Process.Pid)
// Run and wait command
if err := cmd.Wait(); err != nil {
    if _, ok := err.(*exec.ExitError); !ok {
        log.Fatalf("Failed to exit: %s", err)
    }
}

if need exec command in exists namespace:

var pid_i int

// ...

cmd := goclone.Command("/bin/bash")

// ...

pid := strconv.Itoa(pid_i)
cmd.IPCNameSpace = "/proc/" + pid + "/ns/ipc"
cmd.MountNameSpace = "/proc/" + pid + "/ns/mnt"
cmd.NetworkNameSpace = "/proc/" + pid + "/ns/net"
cmd.UTSNameSpace = "/proc/" + pid + "/ns/uts"
cmd.PIDNameSpace = "/proc/" + pid + "/ns/pid"

// ...

Documentation

Overview

This package provides a simple wrapper around the linux 'clone' system call. The aim was to be as compatible with os/exec as possible so this could be used as a direct drop in replacement. Some functionality is improved upon, but mostly this enables several things that can only be done with a wrapper around clone and some added cgo code.

NAME SPACES

This package supports either joining the name spaces of existing processes, or creating whole new name spaces for the process being executed. The current list of supported name spaces include IPC, Mount, Network, PID, and UTS, with PID being special in that its impossible to join a PID name space.

Each of these will isolate the process in some way, for example, removing visibility of the network interfaces on a machine, hiding away other processes, making a whole new file system layout that does not impact other running processes, etc.

For more information see this: http://lwn.net/Articles/531114/

DOUBLE FORKING

This package enables a golang binary to execute another binary by first double forking. This allows the new binary to be a child of initd (pid 1) rather than the calling process. This is very useful for making daemons.

CGROUPS

This package enables a process to be joined into cgroups before it is executed. This ensures that a process can not fork prior to being added or spawn new threads, etc.

OTHER FEATURES

These are features that exist in os/exec as well as this module.

This package also supports changing user credentials via the SysProcAttr field, chrooting the process, writing to non os.File buffers via an automatically created goroutine.

TODO

There are still many things to do within this module: * Examples! * Implement the functionality in SysProcAttr fully. * Finish testing some of the more edge case functionality. * Better documentation. * Warning about user name spaces and setuid being required. * Automatic proc mounting in the child for pid name spaces. * User namespace support in the CLI.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cmd

type Cmd struct {
	// This is the path to the binary that should be executed.
	Path string

	// This is the list of arguments that will be passed to exec, including
	// the command name as Args[0].
	Args []string

	// This is the environment of the process. If this is nil then the
	// environment of the calling process will be used.
	Env []string

	// The working directory of the command. If Dir is empty then the calling
	// processes working directory will be used.
	Dir string

	// This is the io.Reader that will be used as the processes stdin. If this
	// is a os.File object then writing to the descriptor will be done
	// directly, otherwise a goroutine will be started to copy data from the
	// real descriptor to the internal reader.
	Stdin io.Reader

	// These are the io.Writers for Stdout, and Stderr. These work like
	// Stdin in that an os.File object is treated specially and will continue
	// to work even after the golang process has died.
	Stdout io.Writer
	Stderr io.Writer

	// This is a list of extra files that will be passed into the process.
	// these will be mapped in as file  descriptor 3+i. Unlike Stdin these
	// MUST be os.File objects.
	ExtraFiles []*os.File

	// This is a list of system specific attributes. This will be translated
	// into system specific functionally.
	SysProcAttr *syscall.SysProcAttr

	// This is the underlying Process once started.
	Process *os.Process

	// This it the processes state information about the running process.
	ProcessState *os.ProcessState

	// This is a list of cgroups tasks files that should have the new processes
	// pid written into. This is used to ensure that the new process is a
	// member of a specific set of cgroups. If any of these files can not
	// be written to then the child will not be executed.
	CgroupsTasksFiles []string

	// If this is set to true then the clone cycle will double fork. This
	// leaves the new process as a child of initd but means that Wait()
	// will return only when the first child exits, not the second.
	// If setting this it is best to just use Run().
	DoubleFork bool

	// These are name spaces that should be joined by the cloned child
	// before executing the process. This is either empty, or a string
	// of the form "/proc/123/ns/ipc". Note that its impossible to join
	// a PID name space so its not listed here.
	IPCNameSpace     string
	MountNameSpace   string
	NetworkNameSpace string
	UserNameSpace    string
	UTSNameSpace     string
	PIDNameSpace     string

	// These boolean values are used to let the clone system know that it
	// should use the flags that specifically create new name spaces when
	// creating the child process.
	NewIPCNameSpace     bool
	NewMountNameSpace   bool
	NewNetworkNameSpace bool
	NewPIDNameSpace     bool
	NewUserNameSpace    bool
	NewUTSNameSpace     bool

	// If NewUserNameSpace is set to true then these two fields will allow
	// the user map to be defined in the new user namespace. It is an error
	// to define these if NewUserNameSpace is not true. Leaving these as
	// nil will cause gocloen to not alter the user or group settings in
	// the new namespace.
	//
	// An important note here is that the user namespace does not kick in
	// until a call to setuid() and setgid() takes place. As such you
	// should almost always use UserNameSpace and NewUserNameSpace with
	// SysProcAttr set to some UID and GID.
	UserMap  []MapElement
	GroupMap []MapElement

	// Hostname in net ns
	Hostname string

	// If set to true then the child process will create pseudo
	// devices: tty, zero, null, full, random, urandom
	CreatePseudoDevices bool
	// contains filtered or unexported fields
}

This is a structure that mirrors the basic model of os/exec.Cmd but enables a ton of extra very linux specific features via the "clone" system call.

func Command

func Command(cmd string, args ...string) *Cmd

This is a helper function that will create a Cmd object with the given commandline pre-populated.

func (*Cmd) CombinedOutput

func (c *Cmd) CombinedOutput() ([]byte, error)

Returns stdout and stderr combined after running the process.

func (*Cmd) Output

func (c *Cmd) Output() ([]byte, error)

Returns stdout as []bytes after running the process.

func (*Cmd) Run

func (c *Cmd) Run() error

This function wraps a call to Start() and then Wait()

func (*Cmd) Start

func (c *Cmd) Start() (err error)

Run is a simple wrapper around Start() then Wait() with a common err return.

func (*Cmd) StderrPipe

func (c *Cmd) StderrPipe() (io.ReadCloser, error)

StderrPipe returns a pipe that will be connected to the commands stderr.

func (*Cmd) StdinPipe

func (c *Cmd) StdinPipe() (io.WriteCloser, error)

StdinPipe returns a pipe that will be connected to the commands stdin.

func (*Cmd) StdoutPipe

func (c *Cmd) StdoutPipe() (io.ReadCloser, error)

StdoutPipe returns a pipe that will be connected to the commands stdout.

func (*Cmd) Wait

func (c *Cmd) Wait() (err error)

Waits for the process to finish. If Wait() has already been called then this will actually return an error.

type MapElement

type MapElement struct {
	// This is the UID or GID to use inside of the user namespace.
	Inside uint64

	// This is the UID or GID to use outside of the user namespace.
	Outside uint64

	// This sets how many mappings this should cover.
	Length uint64
}

This data element is used to represent a user namespace uid or gid mapping. The three fields are represented in the uid_map or gid_map /proc eitries.

Example: {Inside: 0, Outside: 1000, Length: 4096} Using these settings would make the uid 0 inside of the namespace map to the uid 1000 outside, 1 would map to 1001, so on until 4095 would map to 5095.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL