CreateProcess creates a new task in a new thread group with the given options. The new task has no parent and is in the root PID namespace. If k.Start() has already been called, then the created process must be started by calling kernel.StartProcess(tg). If k.Start() has not yet been called, then
(args CreateProcessArgs)
| 1256 | // Precondition: Caller must take a ref on args.MountNamespace, which is |
| 1257 | // transferred to CreateProcess. |
| 1258 | func (k *Kernel) CreateProcess(args CreateProcessArgs) (*ThreadGroup, ThreadID, error) { |
| 1259 | k.extMu.Lock() |
| 1260 | defer k.extMu.Unlock() |
| 1261 | log.Infof("EXEC: %#v", args.Argv) |
| 1262 | |
| 1263 | ctx := args.NewContext(k) |
| 1264 | mntns := args.MountNamespace |
| 1265 | if mntns == nil { |
| 1266 | if k.globalInit == nil { |
| 1267 | return nil, 0, fmt.Errorf("mount namespace is nil") |
| 1268 | } |
| 1269 | // Add a reference to the namespace, which is transferred to the new process. |
| 1270 | mntns = k.globalInit.Leader().MountNamespace() |
| 1271 | mntns.IncRef() |
| 1272 | } |
| 1273 | // Get the root directory from the MountNamespace. |
| 1274 | root := mntns.Root(ctx) |
| 1275 | defer root.DecRef(ctx) |
| 1276 | refcountCu := cleanup.Make(func() { mntns.DecRef(ctx) }) |
| 1277 | defer refcountCu.Clean() |
| 1278 | |
| 1279 | // Grab the working directory. |
| 1280 | wd := root // Default. |
| 1281 | if args.WorkingDirectory != "" { |
| 1282 | pop := vfs.PathOperation{ |
| 1283 | Root: root, |
| 1284 | Start: wd, |
| 1285 | Path: fspath.Parse(args.WorkingDirectory), |
| 1286 | FollowFinalSymlink: true, |
| 1287 | } |
| 1288 | // NOTE(b/236028361): Do not set CheckSearchable flag to true. |
| 1289 | // Application is allowed to start with a working directory that it can |
| 1290 | // not access/search. This is consistent with Docker and VFS1. Runc |
| 1291 | // explicitly allows for this in 6ce2d63a5db6 ("libct/init_linux: retry |
| 1292 | // chdir to fix EPERM"). As described in the commit, runc unintentionally |
| 1293 | // allowed this behavior in a couple of releases and applications started |
| 1294 | // relying on it. So they decided to allow it for backward compatibility. |
| 1295 | var err error |
| 1296 | wd, err = k.VFS().GetDentryAt(ctx, args.Credentials, &pop, &vfs.GetDentryOptions{}) |
| 1297 | if err != nil { |
| 1298 | return nil, 0, fmt.Errorf("failed to find initial working directory %q: %v", args.WorkingDirectory, err) |
| 1299 | } |
| 1300 | defer wd.DecRef(ctx) |
| 1301 | } |
| 1302 | fsContext := NewFSContext(root, wd, args.Umask) |
| 1303 | refcountCu.Add(func() { fsContext.DecRef(ctx) }) |
| 1304 | |
| 1305 | tg := k.NewThreadGroup(args.PIDNamespace, NewSignalHandlers(), linux.SIGCHLD, args.Limits) |
| 1306 | cu := cleanup.Make(func() { |
| 1307 | tg.Release(ctx) |
| 1308 | }) |
| 1309 | defer cu.Clean() |
| 1310 | |
| 1311 | // Check which file to start from. |
| 1312 | switch { |
| 1313 | case args.Filename != "": |
| 1314 | // If a filename is given, take that. |
| 1315 | // Set File to nil so we resolve the path in LoadTaskImage. |
no test coverage detected