123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- package sysinit
- import (
- "encoding/json"
- "flag"
- "fmt"
- "github.com/dotcloud/docker/netlink"
- "github.com/dotcloud/docker/utils"
- "github.com/syndtr/gocapability/capability"
- "io/ioutil"
- "log"
- "net"
- "os"
- "os/exec"
- "strconv"
- "strings"
- "syscall"
- )
- type DockerInitArgs struct {
- user string
- gateway string
- ip string
- workDir string
- privileged bool
- env []string
- args []string
- }
- func setupHostname(args *DockerInitArgs) error {
- hostname := getEnv(args, "HOSTNAME")
- if hostname == "" {
- return nil
- }
- return setHostname(hostname)
- }
- // Setup networking
- func setupNetworking(args *DockerInitArgs) error {
- if args.ip != "" {
- // eth0
- iface, err := net.InterfaceByName("eth0")
- if err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- ip, ipNet, err := net.ParseCIDR(args.ip)
- if err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- if err := netlink.NetworkLinkAddIp(iface, ip, ipNet); err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- if err := netlink.NetworkLinkUp(iface); err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- // loopback
- iface, err = net.InterfaceByName("lo")
- if err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- if err := netlink.NetworkLinkUp(iface); err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- }
- if args.gateway != "" {
- gw := net.ParseIP(args.gateway)
- if gw == nil {
- return fmt.Errorf("Unable to set up networking, %s is not a valid gateway IP", args.gateway)
- }
- if err := netlink.AddDefaultGw(gw); err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- }
- return nil
- }
- // Setup working directory
- func setupWorkingDirectory(args *DockerInitArgs) error {
- if args.workDir == "" {
- return nil
- }
- if err := syscall.Chdir(args.workDir); err != nil {
- return fmt.Errorf("Unable to change dir to %v: %v", args.workDir, err)
- }
- return nil
- }
- // Takes care of dropping privileges to the desired user
- func changeUser(args *DockerInitArgs) error {
- if args.user == "" {
- return nil
- }
- userent, err := utils.UserLookup(args.user)
- if err != nil {
- return fmt.Errorf("Unable to find user %v: %v", args.user, err)
- }
- uid, err := strconv.Atoi(userent.Uid)
- if err != nil {
- return fmt.Errorf("Invalid uid: %v", userent.Uid)
- }
- gid, err := strconv.Atoi(userent.Gid)
- if err != nil {
- return fmt.Errorf("Invalid gid: %v", userent.Gid)
- }
- if err := syscall.Setgid(gid); err != nil {
- return fmt.Errorf("setgid failed: %v", err)
- }
- if err := syscall.Setuid(uid); err != nil {
- return fmt.Errorf("setuid failed: %v", err)
- }
- return nil
- }
- func setupCapabilities(args *DockerInitArgs) error {
- if args.privileged {
- return nil
- }
- drop := []capability.Cap{
- capability.CAP_SETPCAP,
- capability.CAP_SYS_MODULE,
- capability.CAP_SYS_RAWIO,
- capability.CAP_SYS_PACCT,
- capability.CAP_SYS_ADMIN,
- capability.CAP_SYS_NICE,
- capability.CAP_SYS_RESOURCE,
- capability.CAP_SYS_TIME,
- capability.CAP_SYS_TTY_CONFIG,
- capability.CAP_MKNOD,
- capability.CAP_AUDIT_WRITE,
- capability.CAP_AUDIT_CONTROL,
- capability.CAP_MAC_OVERRIDE,
- capability.CAP_MAC_ADMIN,
- }
- c, err := capability.NewPid(os.Getpid())
- if err != nil {
- return err
- }
- c.Unset(capability.CAPS|capability.BOUNDS, drop...)
- if err := c.Apply(capability.CAPS | capability.BOUNDS); err != nil {
- return err
- }
- return nil
- }
- // Clear environment pollution introduced by lxc-start
- func setupEnv(args *DockerInitArgs) {
- os.Clearenv()
- for _, kv := range args.env {
- parts := strings.SplitN(kv, "=", 2)
- if len(parts) == 1 {
- parts = append(parts, "")
- }
- os.Setenv(parts[0], parts[1])
- }
- }
- func getEnv(args *DockerInitArgs, key string) string {
- for _, kv := range args.env {
- parts := strings.SplitN(kv, "=", 2)
- if parts[0] == key && len(parts) == 2 {
- return parts[1]
- }
- }
- return ""
- }
- func executeProgram(args *DockerInitArgs) error {
- setupEnv(args)
- if err := setupHostname(args); err != nil {
- return err
- }
- if err := setupNetworking(args); err != nil {
- return err
- }
- if err := setupCapabilities(args); err != nil {
- return err
- }
- if err := setupWorkingDirectory(args); err != nil {
- return err
- }
- if err := changeUser(args); err != nil {
- return err
- }
- path, err := exec.LookPath(args.args[0])
- if err != nil {
- log.Printf("Unable to locate %v", args.args[0])
- os.Exit(127)
- }
- if err := syscall.Exec(path, args.args, os.Environ()); err != nil {
- panic(err)
- }
- // Will never reach here
- return nil
- }
- // Sys Init code
- // This code is run INSIDE the container and is responsible for setting
- // up the environment before running the actual process
- func SysInit() {
- if len(os.Args) <= 1 {
- fmt.Println("You should not invoke dockerinit manually")
- os.Exit(1)
- }
- // Get cmdline arguments
- user := flag.String("u", "", "username or uid")
- gateway := flag.String("g", "", "gateway address")
- ip := flag.String("i", "", "ip address")
- workDir := flag.String("w", "", "workdir")
- privileged := flag.Bool("privileged", false, "privileged mode")
- flag.Parse()
- // Get env
- var env []string
- content, err := ioutil.ReadFile("/.dockerenv")
- if err != nil {
- log.Fatalf("Unable to load environment variables: %v", err)
- }
- if err := json.Unmarshal(content, &env); err != nil {
- log.Fatalf("Unable to unmarshal environment variables: %v", err)
- }
- // Propagate the plugin-specific container env variable
- env = append(env, "container="+os.Getenv("container"))
- args := &DockerInitArgs{
- user: *user,
- gateway: *gateway,
- ip: *ip,
- workDir: *workDir,
- privileged: *privileged,
- env: env,
- args: flag.Args(),
- }
- if err := executeProgram(args); err != nil {
- log.Fatal(err)
- }
- }
|