sysinit.go 4.7 KB

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