prepareRootfs sets up the devices, mount points, and filesystems for use inside a new mount namespace. It doesn't set anything as ro. You must call finalizeRootfs after this function to finish setting up the rootfs.
(pipe *syncSocket, iConfig *initConfig)
| 168 | // inside a new mount namespace. It doesn't set anything as ro. You must call |
| 169 | // finalizeRootfs after this function to finish setting up the rootfs. |
| 170 | func prepareRootfs(pipe *syncSocket, iConfig *initConfig) (err error) { |
| 171 | config := iConfig.Config |
| 172 | if err := prepareRoot(config); err != nil { |
| 173 | return fmt.Errorf("error preparing rootfs: %w", err) |
| 174 | } |
| 175 | |
| 176 | // Pre-open rootfs. NOTE that if we need to re-enable support for mounting |
| 177 | // on top of container root (see issue 5070), we will need to reopen rootFd |
| 178 | // after such mounts. |
| 179 | rootFd, err := os.OpenFile(config.Rootfs, unix.O_DIRECTORY|unix.O_CLOEXEC|unix.O_PATH, 0) |
| 180 | if err != nil { |
| 181 | return fmt.Errorf("open rootfs handle: %w", err) |
| 182 | } |
| 183 | defer rootFd.Close() |
| 184 | |
| 185 | mountConfig := &mountConfig{ |
| 186 | root: rootFd, |
| 187 | label: config.MountLabel, |
| 188 | cgroup2Path: iConfig.Cgroup2Path, |
| 189 | rootlessCgroups: config.RootlessCgroups, |
| 190 | cgroupns: config.Namespaces.Contains(configs.NEWCGROUP), |
| 191 | } |
| 192 | for _, m := range config.Mounts { |
| 193 | if err := setupAndMountToRootfs(pipe, config, mountConfig, m); err != nil { |
| 194 | return err |
| 195 | } |
| 196 | } |
| 197 | |
| 198 | setupDev := needsSetupDev(config) |
| 199 | if setupDev { |
| 200 | if err := doSetupDev(rootFd, config); err != nil { |
| 201 | return fmt.Errorf("configuring container /dev: %w", err) |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | // Signal the parent to run the pre-start hooks. |
| 206 | // The hooks are run after the mounts are setup, but before we switch to the new |
| 207 | // root, so that the old root is still available in the hooks for any mount |
| 208 | // manipulations. |
| 209 | // Note that iConfig.Cwd is not guaranteed to exist here. |
| 210 | if err := syncParentHooks(pipe); err != nil { |
| 211 | return err |
| 212 | } |
| 213 | |
| 214 | // The reason these operations are done here rather than in finalizeRootfs |
| 215 | // is because the console-handling code gets quite sticky if we have to set |
| 216 | // up the console before doing the pivot_root(2). This is because the |
| 217 | // Console API has to also work with the ExecIn case, which means that the |
| 218 | // API must be able to deal with being inside as well as outside the |
| 219 | // container. It's just cleaner to do this here (at the expense of the |
| 220 | // operation not being perfectly split). |
| 221 | |
| 222 | if err := unix.Fchdir(int(rootFd.Fd())); err != nil { |
| 223 | return &os.PathError{Op: "chdir", Path: config.Rootfs, Err: err} |
| 224 | } |
| 225 | |
| 226 | if s := iConfig.SpecState; s != nil { |
| 227 | s.Pid = unix.Getpid() |
no test coverage detected
searching dependent graphs…