sysinit.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package sysinit
  2. import (
  3. "encoding/json"
  4. "flag"
  5. "fmt"
  6. "github.com/dotcloud/docker/netlink"
  7. "github.com/dotcloud/docker/utils"
  8. "github.com/syndtr/gocapability/capability"
  9. "io/ioutil"
  10. "log"
  11. "net"
  12. "os"
  13. "os/exec"
  14. "strconv"
  15. "strings"
  16. "syscall"
  17. )
  18. type DockerInitArgs struct {
  19. user string
  20. gateway string
  21. workDir string
  22. privileged bool
  23. env []string
  24. args []string
  25. }
  26. // Setup networking
  27. func setupNetworking(args *DockerInitArgs) error {
  28. if args.gateway == "" {
  29. return nil
  30. }
  31. ip := net.ParseIP(args.gateway)
  32. if ip == nil {
  33. return fmt.Errorf("Unable to set up networking, %s is not a valid IP", args.gateway)
  34. }
  35. if err := netlink.AddDefaultGw(ip); err != nil {
  36. return fmt.Errorf("Unable to set up networking: %v", err)
  37. }
  38. return nil
  39. }
  40. // Setup working directory
  41. func setupWorkingDirectory(args *DockerInitArgs) error {
  42. if args.workDir == "" {
  43. return nil
  44. }
  45. if err := syscall.Chdir(args.workDir); err != nil {
  46. return fmt.Errorf("Unable to change dir to %v: %v", args.workDir, err)
  47. }
  48. return nil
  49. }
  50. // Takes care of dropping privileges to the desired user
  51. func changeUser(args *DockerInitArgs) error {
  52. if args.user == "" {
  53. return nil
  54. }
  55. userent, err := utils.UserLookup(args.user)
  56. if err != nil {
  57. return fmt.Errorf("Unable to find user %v: %v", args.user, err)
  58. }
  59. uid, err := strconv.Atoi(userent.Uid)
  60. if err != nil {
  61. return fmt.Errorf("Invalid uid: %v", userent.Uid)
  62. }
  63. gid, err := strconv.Atoi(userent.Gid)
  64. if err != nil {
  65. return fmt.Errorf("Invalid gid: %v", userent.Gid)
  66. }
  67. if err := syscall.Setgid(gid); err != nil {
  68. return fmt.Errorf("setgid failed: %v", err)
  69. }
  70. if err := syscall.Setuid(uid); err != nil {
  71. return fmt.Errorf("setuid failed: %v", err)
  72. }
  73. return nil
  74. }
  75. func setupCapabilities(args *DockerInitArgs) error {
  76. if args.privileged {
  77. return nil
  78. }
  79. drop := []capability.Cap{
  80. capability.CAP_SETPCAP,
  81. capability.CAP_SYS_MODULE,
  82. capability.CAP_SYS_RAWIO,
  83. capability.CAP_SYS_PACCT,
  84. capability.CAP_SYS_ADMIN,
  85. capability.CAP_SYS_NICE,
  86. capability.CAP_SYS_RESOURCE,
  87. capability.CAP_SYS_TIME,
  88. capability.CAP_SYS_TTY_CONFIG,
  89. capability.CAP_MKNOD,
  90. capability.CAP_AUDIT_WRITE,
  91. capability.CAP_AUDIT_CONTROL,
  92. capability.CAP_MAC_OVERRIDE,
  93. capability.CAP_MAC_ADMIN,
  94. }
  95. c, err := capability.NewPid(os.Getpid())
  96. if err != nil {
  97. return err
  98. }
  99. c.Unset(capability.CAPS|capability.BOUNDS, drop...)
  100. if err := c.Apply(capability.CAPS | capability.BOUNDS); err != nil {
  101. return err
  102. }
  103. return nil
  104. }
  105. // Clear environment pollution introduced by lxc-start
  106. func setupEnv(args *DockerInitArgs) {
  107. os.Clearenv()
  108. for _, kv := range args.env {
  109. parts := strings.SplitN(kv, "=", 2)
  110. if len(parts) == 1 {
  111. parts = append(parts, "")
  112. }
  113. os.Setenv(parts[0], parts[1])
  114. }
  115. }
  116. func executeProgram(args *DockerInitArgs) error {
  117. setupEnv(args)
  118. if err := setupNetworking(args); err != nil {
  119. return err
  120. }
  121. if err := setupCapabilities(args); err != nil {
  122. return err
  123. }
  124. if err := setupWorkingDirectory(args); err != nil {
  125. return err
  126. }
  127. if err := changeUser(args); err != nil {
  128. return err
  129. }
  130. path, err := exec.LookPath(args.args[0])
  131. if err != nil {
  132. log.Printf("Unable to locate %v", args.args[0])
  133. os.Exit(127)
  134. }
  135. if err := syscall.Exec(path, args.args, os.Environ()); err != nil {
  136. panic(err)
  137. }
  138. // Will never reach here
  139. return nil
  140. }
  141. // Sys Init code
  142. // This code is run INSIDE the container and is responsible for setting
  143. // up the environment before running the actual process
  144. func SysInit() {
  145. if len(os.Args) <= 1 {
  146. fmt.Println("You should not invoke dockerinit manually")
  147. os.Exit(1)
  148. }
  149. // Get cmdline arguments
  150. user := flag.String("u", "", "username or uid")
  151. gateway := flag.String("g", "", "gateway address")
  152. workDir := flag.String("w", "", "workdir")
  153. privileged := flag.Bool("privileged", false, "privileged mode")
  154. flag.Parse()
  155. // Get env
  156. var env []string
  157. content, err := ioutil.ReadFile("/.dockerenv")
  158. if err != nil {
  159. log.Fatalf("Unable to load environment variables: %v", err)
  160. }
  161. if err := json.Unmarshal(content, &env); err != nil {
  162. log.Fatalf("Unable to unmarshal environment variables: %v", err)
  163. }
  164. args := &DockerInitArgs{
  165. user: *user,
  166. gateway: *gateway,
  167. workDir: *workDir,
  168. privileged: *privileged,
  169. env: env,
  170. args: flag.Args(),
  171. }
  172. if err := executeProgram(args); err != nil {
  173. log.Fatal(err)
  174. }
  175. }