sysinit.go 5.7 KB

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