Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / opencontainers / runc / libcontainer / init_linux.go
1 // +build linux
2
3 package libcontainer
4
5 import (
6         "encoding/json"
7         "fmt"
8         "io"
9         "net"
10         "os"
11         "strings"
12         "syscall"
13         "unsafe"
14
15         "github.com/Sirupsen/logrus"
16         "github.com/opencontainers/runc/libcontainer/cgroups"
17         "github.com/opencontainers/runc/libcontainer/configs"
18         "github.com/opencontainers/runc/libcontainer/system"
19         "github.com/opencontainers/runc/libcontainer/user"
20         "github.com/opencontainers/runc/libcontainer/utils"
21         "github.com/vishvananda/netlink"
22 )
23
24 type initType string
25
26 const (
27         initSetns    initType = "setns"
28         initStandard initType = "standard"
29 )
30
31 type pid struct {
32         Pid int `json:"pid"`
33 }
34
35 // network is an internal struct used to setup container networks.
36 type network struct {
37         configs.Network
38
39         // TempVethPeerName is a unique temporary veth peer name that was placed into
40         // the container's namespace.
41         TempVethPeerName string `json:"temp_veth_peer_name"`
42 }
43
44 // initConfig is used for transferring parameters from Exec() to Init()
45 type initConfig struct {
46         Args             []string              `json:"args"`
47         Env              []string              `json:"env"`
48         Cwd              string                `json:"cwd"`
49         Capabilities     *configs.Capabilities `json:"capabilities"`
50         ProcessLabel     string                `json:"process_label"`
51         AppArmorProfile  string                `json:"apparmor_profile"`
52         NoNewPrivileges  bool                  `json:"no_new_privileges"`
53         User             string                `json:"user"`
54         AdditionalGroups []string              `json:"additional_groups"`
55         Config           *configs.Config       `json:"config"`
56         Networks         []*network            `json:"network"`
57         PassedFilesCount int                   `json:"passed_files_count"`
58         ContainerId      string                `json:"containerid"`
59         Rlimits          []configs.Rlimit      `json:"rlimits"`
60         CreateConsole    bool                  `json:"create_console"`
61         Rootless         bool                  `json:"rootless"`
62 }
63
64 type initer interface {
65         Init() error
66 }
67
68 func newContainerInit(t initType, pipe *os.File, consoleSocket *os.File, stateDirFD int) (initer, error) {
69         var config *initConfig
70         if err := json.NewDecoder(pipe).Decode(&config); err != nil {
71                 return nil, err
72         }
73         if err := populateProcessEnvironment(config.Env); err != nil {
74                 return nil, err
75         }
76         switch t {
77         case initSetns:
78                 return &linuxSetnsInit{
79                         pipe:          pipe,
80                         consoleSocket: consoleSocket,
81                         config:        config,
82                 }, nil
83         case initStandard:
84                 return &linuxStandardInit{
85                         pipe:          pipe,
86                         consoleSocket: consoleSocket,
87                         parentPid:     syscall.Getppid(),
88                         config:        config,
89                         stateDirFD:    stateDirFD,
90                 }, nil
91         }
92         return nil, fmt.Errorf("unknown init type %q", t)
93 }
94
95 // populateProcessEnvironment loads the provided environment variables into the
96 // current processes's environment.
97 func populateProcessEnvironment(env []string) error {
98         for _, pair := range env {
99                 p := strings.SplitN(pair, "=", 2)
100                 if len(p) < 2 {
101                         return fmt.Errorf("invalid environment '%v'", pair)
102                 }
103                 if err := os.Setenv(p[0], p[1]); err != nil {
104                         return err
105                 }
106         }
107         return nil
108 }
109
110 // finalizeNamespace drops the caps, sets the correct user
111 // and working dir, and closes any leaked file descriptors
112 // before executing the command inside the namespace
113 func finalizeNamespace(config *initConfig) error {
114         // Ensure that all unwanted fds we may have accidentally
115         // inherited are marked close-on-exec so they stay out of the
116         // container
117         if err := utils.CloseExecFrom(config.PassedFilesCount + 3); err != nil {
118                 return err
119         }
120
121         capabilities := &configs.Capabilities{}
122         if config.Capabilities != nil {
123                 capabilities = config.Capabilities
124         } else if config.Config.Capabilities != nil {
125                 capabilities = config.Config.Capabilities
126         }
127         w, err := newContainerCapList(capabilities)
128         if err != nil {
129                 return err
130         }
131         // drop capabilities in bounding set before changing user
132         if err := w.ApplyBoundingSet(); err != nil {
133                 return err
134         }
135         // preserve existing capabilities while we change users
136         if err := system.SetKeepCaps(); err != nil {
137                 return err
138         }
139         if err := setupUser(config); err != nil {
140                 return err
141         }
142         if err := system.ClearKeepCaps(); err != nil {
143                 return err
144         }
145         if err := w.ApplyCaps(); err != nil {
146                 return err
147         }
148         if config.Cwd != "" {
149                 if err := syscall.Chdir(config.Cwd); err != nil {
150                         return fmt.Errorf("chdir to cwd (%q) set in config.json failed: %v", config.Cwd, err)
151                 }
152         }
153         return nil
154 }
155
156 // setupConsole sets up the console from inside the container, and sends the
157 // master pty fd to the config.Pipe (using cmsg). This is done to ensure that
158 // consoles are scoped to a container properly (see runc#814 and the many
159 // issues related to that). This has to be run *after* we've pivoted to the new
160 // rootfs (and the users' configuration is entirely set up).
161 func setupConsole(socket *os.File, config *initConfig, mount bool) error {
162         defer socket.Close()
163         // At this point, /dev/ptmx points to something that we would expect. We
164         // used to change the owner of the slave path, but since the /dev/pts mount
165         // can have gid=X set (at the users' option). So touching the owner of the
166         // slave PTY is not necessary, as the kernel will handle that for us. Note
167         // however, that setupUser (specifically fixStdioPermissions) *will* change
168         // the UID owner of the console to be the user the process will run as (so
169         // they can actually control their console).
170         console, err := newConsole()
171         if err != nil {
172                 return err
173         }
174         // After we return from here, we don't need the console anymore.
175         defer console.Close()
176
177         linuxConsole, ok := console.(*linuxConsole)
178         if !ok {
179                 return fmt.Errorf("failed to cast console to *linuxConsole")
180         }
181         // Mount the console inside our rootfs.
182         if mount {
183                 if err := linuxConsole.mount(); err != nil {
184                         return err
185                 }
186         }
187         // While we can access console.master, using the API is a good idea.
188         if err := utils.SendFd(socket, linuxConsole.File()); err != nil {
189                 return err
190         }
191         // Now, dup over all the things.
192         return linuxConsole.dupStdio()
193 }
194
195 // syncParentReady sends to the given pipe a JSON payload which indicates that
196 // the init is ready to Exec the child process. It then waits for the parent to
197 // indicate that it is cleared to Exec.
198 func syncParentReady(pipe io.ReadWriter) error {
199         // Tell parent.
200         if err := writeSync(pipe, procReady); err != nil {
201                 return err
202         }
203
204         // Wait for parent to give the all-clear.
205         if err := readSync(pipe, procRun); err != nil {
206                 return err
207         }
208
209         return nil
210 }
211
212 // syncParentHooks sends to the given pipe a JSON payload which indicates that
213 // the parent should execute pre-start hooks. It then waits for the parent to
214 // indicate that it is cleared to resume.
215 func syncParentHooks(pipe io.ReadWriter) error {
216         // Tell parent.
217         if err := writeSync(pipe, procHooks); err != nil {
218                 return err
219         }
220
221         // Wait for parent to give the all-clear.
222         if err := readSync(pipe, procResume); err != nil {
223                 return err
224         }
225
226         return nil
227 }
228
229 // setupUser changes the groups, gid, and uid for the user inside the container
230 func setupUser(config *initConfig) error {
231         // Set up defaults.
232         defaultExecUser := user.ExecUser{
233                 Uid:  0,
234                 Gid:  0,
235                 Home: "/",
236         }
237
238         passwdPath, err := user.GetPasswdPath()
239         if err != nil {
240                 return err
241         }
242
243         groupPath, err := user.GetGroupPath()
244         if err != nil {
245                 return err
246         }
247
248         execUser, err := user.GetExecUserPath(config.User, &defaultExecUser, passwdPath, groupPath)
249         if err != nil {
250                 return err
251         }
252
253         var addGroups []int
254         if len(config.AdditionalGroups) > 0 {
255                 addGroups, err = user.GetAdditionalGroupsPath(config.AdditionalGroups, groupPath)
256                 if err != nil {
257                         return err
258                 }
259         }
260
261         if config.Rootless {
262                 if execUser.Uid != 0 {
263                         return fmt.Errorf("cannot run as a non-root user in a rootless container")
264                 }
265
266                 if execUser.Gid != 0 {
267                         return fmt.Errorf("cannot run as a non-root group in a rootless container")
268                 }
269
270                 // We cannot set any additional groups in a rootless container and thus we
271                 // bail if the user asked us to do so. TODO: We currently can't do this
272                 // earlier, but if libcontainer.Process.User was typesafe this might work.
273                 if len(addGroups) > 0 {
274                         return fmt.Errorf("cannot set any additional groups in a rootless container")
275                 }
276         }
277
278         // before we change to the container's user make sure that the processes STDIO
279         // is correctly owned by the user that we are switching to.
280         if err := fixStdioPermissions(config, execUser); err != nil {
281                 return err
282         }
283
284         // This isn't allowed in an unprivileged user namespace since Linux 3.19.
285         // There's nothing we can do about /etc/group entries, so we silently
286         // ignore setting groups here (since the user didn't explicitly ask us to
287         // set the group).
288         if !config.Rootless {
289                 suppGroups := append(execUser.Sgids, addGroups...)
290                 if err := syscall.Setgroups(suppGroups); err != nil {
291                         return err
292                 }
293         }
294
295         if err := system.Setgid(execUser.Gid); err != nil {
296                 return err
297         }
298
299         if err := system.Setuid(execUser.Uid); err != nil {
300                 return err
301         }
302
303         // if we didn't get HOME already, set it based on the user's HOME
304         if envHome := os.Getenv("HOME"); envHome == "" {
305                 if err := os.Setenv("HOME", execUser.Home); err != nil {
306                         return err
307                 }
308         }
309         return nil
310 }
311
312 // fixStdioPermissions fixes the permissions of PID 1's STDIO within the container to the specified user.
313 // The ownership needs to match because it is created outside of the container and needs to be
314 // localized.
315 func fixStdioPermissions(config *initConfig, u *user.ExecUser) error {
316         var null syscall.Stat_t
317         if err := syscall.Stat("/dev/null", &null); err != nil {
318                 return err
319         }
320         for _, fd := range []uintptr{
321                 os.Stdin.Fd(),
322                 os.Stderr.Fd(),
323                 os.Stdout.Fd(),
324         } {
325                 var s syscall.Stat_t
326                 if err := syscall.Fstat(int(fd), &s); err != nil {
327                         return err
328                 }
329
330                 // Skip chown of /dev/null if it was used as one of the STDIO fds.
331                 if s.Rdev == null.Rdev {
332                         continue
333                 }
334
335                 // Skip chown if s.Gid is actually an unmapped gid in the host. While
336                 // this is a bit dodgy if it just so happens that the console _is_
337                 // owned by overflow_gid, there's no way for us to disambiguate this as
338                 // a userspace program.
339                 if _, err := config.Config.HostGID(int(s.Gid)); err != nil {
340                         continue
341                 }
342
343                 // We only change the uid owner (as it is possible for the mount to
344                 // prefer a different gid, and there's no reason for us to change it).
345                 // The reason why we don't just leave the default uid=X mount setup is
346                 // that users expect to be able to actually use their console. Without
347                 // this code, you couldn't effectively run as a non-root user inside a
348                 // container and also have a console set up.
349                 if err := syscall.Fchown(int(fd), u.Uid, int(s.Gid)); err != nil {
350                         return err
351                 }
352         }
353         return nil
354 }
355
356 // setupNetwork sets up and initializes any network interface inside the container.
357 func setupNetwork(config *initConfig) error {
358         for _, config := range config.Networks {
359                 strategy, err := getStrategy(config.Type)
360                 if err != nil {
361                         return err
362                 }
363                 if err := strategy.initialize(config); err != nil {
364                         return err
365                 }
366         }
367         return nil
368 }
369
370 func setupRoute(config *configs.Config) error {
371         for _, config := range config.Routes {
372                 _, dst, err := net.ParseCIDR(config.Destination)
373                 if err != nil {
374                         return err
375                 }
376                 src := net.ParseIP(config.Source)
377                 if src == nil {
378                         return fmt.Errorf("Invalid source for route: %s", config.Source)
379                 }
380                 gw := net.ParseIP(config.Gateway)
381                 if gw == nil {
382                         return fmt.Errorf("Invalid gateway for route: %s", config.Gateway)
383                 }
384                 l, err := netlink.LinkByName(config.InterfaceName)
385                 if err != nil {
386                         return err
387                 }
388                 route := &netlink.Route{
389                         Scope:     netlink.SCOPE_UNIVERSE,
390                         Dst:       dst,
391                         Src:       src,
392                         Gw:        gw,
393                         LinkIndex: l.Attrs().Index,
394                 }
395                 if err := netlink.RouteAdd(route); err != nil {
396                         return err
397                 }
398         }
399         return nil
400 }
401
402 func setupRlimits(limits []configs.Rlimit, pid int) error {
403         for _, rlimit := range limits {
404                 if err := system.Prlimit(pid, rlimit.Type, syscall.Rlimit{Max: rlimit.Hard, Cur: rlimit.Soft}); err != nil {
405                         return fmt.Errorf("error setting rlimit type %v: %v", rlimit.Type, err)
406                 }
407         }
408         return nil
409 }
410
411 const _P_PID = 1
412
413 type siginfo struct {
414         si_signo int32
415         si_errno int32
416         si_code  int32
417         // below here is a union; si_pid is the only field we use
418         si_pid int32
419         // Pad to 128 bytes as detailed in blockUntilWaitable
420         pad [96]byte
421 }
422
423 // isWaitable returns true if the process has exited false otherwise.
424 // Its based off blockUntilWaitable in src/os/wait_waitid.go
425 func isWaitable(pid int) (bool, error) {
426         si := &siginfo{}
427         _, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(pid), uintptr(unsafe.Pointer(si)), syscall.WEXITED|syscall.WNOWAIT|syscall.WNOHANG, 0, 0)
428         if e != 0 {
429                 return false, os.NewSyscallError("waitid", e)
430         }
431
432         return si.si_pid != 0, nil
433 }
434
435 // isNoChildren returns true if err represents a syscall.ECHILD false otherwise
436 func isNoChildren(err error) bool {
437         switch err := err.(type) {
438         case syscall.Errno:
439                 if err == syscall.ECHILD {
440                         return true
441                 }
442         case *os.SyscallError:
443                 if err.Err == syscall.ECHILD {
444                         return true
445                 }
446         }
447         return false
448 }
449
450 // signalAllProcesses freezes then iterates over all the processes inside the
451 // manager's cgroups sending the signal s to them.
452 // If s is SIGKILL then it will wait for each process to exit.
453 // For all other signals it will check if the process is ready to report its
454 // exit status and only if it is will a wait be performed.
455 func signalAllProcesses(m cgroups.Manager, s os.Signal) error {
456         var procs []*os.Process
457         if err := m.Freeze(configs.Frozen); err != nil {
458                 logrus.Warn(err)
459         }
460         pids, err := m.GetAllPids()
461         if err != nil {
462                 m.Freeze(configs.Thawed)
463                 return err
464         }
465         for _, pid := range pids {
466                 p, err := os.FindProcess(pid)
467                 if err != nil {
468                         logrus.Warn(err)
469                         continue
470                 }
471                 procs = append(procs, p)
472                 if err := p.Signal(s); err != nil {
473                         logrus.Warn(err)
474                 }
475         }
476         if err := m.Freeze(configs.Thawed); err != nil {
477                 logrus.Warn(err)
478         }
479
480         for _, p := range procs {
481                 if s != syscall.SIGKILL {
482                         if ok, err := isWaitable(p.Pid); err != nil {
483                                 if !isNoChildren(err) {
484                                         logrus.Warn("signalAllProcesses: ", p.Pid, err)
485                                 }
486                                 continue
487                         } else if !ok {
488                                 // Not ready to report so don't wait
489                                 continue
490                         }
491                 }
492
493                 if _, err := p.Wait(); err != nil {
494                         if !isNoChildren(err) {
495                                 logrus.Warn("wait: ", err)
496                         }
497                 }
498         }
499         return nil
500 }