Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to analyze namespace with runC source code

2025-02-25 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)05/31 Report--

How to use runC source code to analyze namespace, I believe that many inexperienced people are at a loss about this. Therefore, this paper summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.

The Namespaces corresponding to container is defined in runc/libcontainer/configs/config.go. For User Namespaces, UidMappings and GidMappings for user map are also defined.

/ / Config defines configuration options for executing a process inside a contained environment.type Config struct {/ / Namespaces specifies the container's namespaces that it should setup when cloning the init process / / If a namespace is not provided that namespace is shared from the container's parent process Namespaces Namespaces `json: "namespaces" `/ / UidMappings is an array of User ID mappings for User Namespaces UidMappings [] IDMap `json: "uid_mappings"` / / GidMappings is an array of Group ID mappings for User Namespaces GidMappings [] IDMap `json: "gid_mappings" `...}

The source code of namespace in runC is mainly as follows: namespce type supported by runc/libcontainer/configs/namespaces_unix.go runC includes ($nsName) "net", "mnt", "pid", "ipc", "user", "uts":

Const (NEWNET NamespaceType = "NEWNET" NEWPID NamespaceType = "NEWPID" NEWNS NamespaceType = "NEWNS" NEWUTS NamespaceType = "NEWUTS" NEWIPC NamespaceType = "NEWIPC" NEWUSER NamespaceType = "NEWUSER")

In addition to verifying whether Namespce Type is in the above constant, but also to verify that / proc/self/ns/$nsName exists and can read, it is considered that the Namespace is supported in the current system.

/ / IsNamespaceSupported returns whether a namespace is available or// notfunc IsNamespaceSupported (ns NamespaceType) bool {... Supported, ok: = supportedNamespaces [ns] if ok {return supported}. / / in addition to verifying that Namespce Type is in the specified list, verify that / proc/self/ns/$nsName exists and can read _, err: = os.Stat (fmt.Sprintf ("/ proc/self/ns/%s", nsFile)) supported = err = = nil. Return supported}

The following is the complete definition of NameSpace, which is simple and includes only NamespaceType and the corresponding Path.

/ / Namespace defines configuration for each namespace. It specifies an// alternate path that is able to be joined via setns.type Namespace struct {Type NamespaceType `json: "type" `Path string `json: "path" `}

As you can see from the GetPath method of Namespace, the namespace path corresponding to a pid is / proc/$pid/ns/$nsName.

Func (n * Namespace) GetPath (pid int) string {if n.Path! = "" {return n.Path} return fmt.Sprintf ("/ proc/%d/ns/%s", pid, NsName (n.Type))}

In addition, the following common methods are defined:

Func (n * Namespaces) Remove (t NamespaceType) bool {.} func (n * Namespaces) Add (t NamespaceType, path string) {.} func (n * Namespaces) index (t NamespaceType) int {.} func (n * Namespaces) Contains (t NamespaceType) bool {.} func (n * Namespaces) PathOf (t NamespaceType) string {.}

In runc/libcontainer/configs/namespaces_syscall.go, the clone flags corresponding to these namespace when linux clone is defined.

Var namespaceInfo = map [NamespaceType] int {NEWNET: syscall.CLONE_NEWNET, NEWNS: syscall.CLONE_NEWNS, NEWUSER: syscall.CLONE_NEWUSER, NEWIPC: syscall.CLONE_NEWIPC, NEWUTS: syscall.CLONE_NEWUTS, NEWPID: syscall.CLONE_NEWPID,} / / CloneFlags parses the container's Namespaces options to set the correct// flags on clone, unshare. This function returns flags only for new namespaces.func (n * Namespaces) CloneFlags () uintptr {var flag int for _, v: = range * n {if v.Path! = "" {continue} flag | = namespaceInfo [v.Type]} return uintptr (flag)}

The above CloneFlags () method is used to parse the namespace-related parameters in the config of linuxContainer, generate clone flags, and provide it to linuxContainer.bootstrapData (cloneFlags uintptr, nsMaps map [configs.NamespaceType] string) for encapsulation.

/ / bootstrapData encodes the necessary data in netlink binary format// as an io.Reader.// Consumer can write the data to a bootstrap program// such as one that uses nsenter package to bootstrap the container's// init process correctly, i.e. With correct namespaces, uid/gid// mapping etc.func (c * linuxContainer) bootstrapData (cloneFlags uintptr, nsMaps map [configs.NamespaceType] string) (io.Reader, error) {/ / create the netlink message r: = nl.NewNetlinkRequest (int (InitMsg)) 0) / / write cloneFlags r.AddData (& Int32msg {Type: CloneFlagsAttr, Value: uint32 (cloneFlags),}) / / write custom namespace paths if len (nsMaps) > 0 {nsPaths, err: = c.orderNamespacePaths (nsMaps) if err! = nil {return nil Err} r.AddData (& Bytemsg {Type: NsPathsAttr, Value: [] byte (strings.Join (nsPaths, ",),})} / / write namespace paths only when we are not joining an existing user ns _ JoinExistingUser: = nsMaps [configs.NEWUSER] if! joinExistingUser {/ / write uid mappings if len (c.config.UidMappings) > 0 {b, err: = encodeIDMapping (c.config.UidMappings) if err! = nil {return nil Err} r.AddData (& Bytemsg {Type: UidmapAttr, Value: B,})} / / write gid mappings if len (c.config.GidMappings) > 0 {b Err: = encodeIDMapping (c.config.GidMappings) if err! = nil {return nil, err} r.AddData (& Bytemsg {Type: GidmapAttr, Value: B }) / / check if we have CAP_SETGID to setgroup properly pid, err: = capability.NewPid (os.Getpid ()) if err! = nil {return nil, err} if! pid.Get (capability.EFFECTIVE Capability.CAP_SETGID) {r.AddData (& Boolmsg {Type: SetgroupAttr, Value: true,})} return bytes.NewReader (r.Serialize ()), nil}

LinuxContainer.newInitProcess (...) Eventually, the clone flags data encapsulated by linuxContainer.bootstrapData will be used to complete the construction of initProcess.

Func (c * linuxContainer) newInitProcess (p * Process, cmd * exec.Cmd, parentPipe, childPipe, rootDir * os.File) (* initProcess, error) {cmd.Env = append (cmd.Env, "_ LIBCONTAINER_INITTYPE=" + string (initStandard) nsMaps: = make (map [configs. NamespaceType] string) for _ Ns: = range c.config.Namespaces {if ns.Path! = "" {nsMaps [ns.Type] = ns.Path}} _, sharePidns: = nsMaps [configs.NEWPID] data, err: = c.bootstrapData (c.config.Namespaces.CloneFlags (), nsMaps) if err! = nil {return nil Err} p.consoleChan = make (chan * os.File, 1) return & initProcess {cmd: cmd, childPipe: childPipe, parentPipe: parentPipe, manager: c.cgroupManager, config: c.newInitConfig (p), container: C Process: p, bootstrapData: data, sharePidns: sharePidns, rootDir: rootDir,}, nil}

NewInitProcess (...) For the position in the whole container create process, please refer to the Create/Run Container of runC source code analysis-Wang Tao, the source code analysis of namespace in the whole container create/run is complete.

Add: the Spec of container in runC is parsed from bundle/config.json. See the call to setupSpec (context) in runC's create.go.

Action: func (context * cli.Context) error {if context.NArg ()! = 1 {fmt.Printf ("Incorrect Usage.\ n\ n") cli.ShowCommandHelp (context, "create") return fmt.Errorf ("runc:\" create\ "requires exactly one argument")} if err: = revisePidFile (context) Err! = nil {return err} spec, err: = setupSpec (context) if err! = nil {return err} status, err: = startContainer (context, spec, true) if err! = nil {return err}

SetupSepc (context) will go to loadSpec ("config.json"):

/ / setupSpec performs initial setup based on the cli.Context for the containerfunc setupSpec (context * cli.Context) (* specs.Spec, error) {bundle: = context.String ("bundle") if bundle! = "" {if err: = os.Chdir (bundle) Err! = nil {return nil, err}} spec, err: = loadSpec (specConfig) if err! = nil {return nil, err} notifySocket: = os.Getenv ("NOTIFY_SOCKET") if notifySocket! = "{setupSdNotify (spec) NotifySocket)} if os.Geteuid ()! = 0 {return nil, fmt.Errorf ("runc should be run as root")} return spec, nil}

The sample config.json is as follows, and see ".linux.namespaces" in the namespace section.

{"ociVersion": "0.4.0", "platform": {"os": "linux", "arch": "amd64"}, "process": {"terminal": true, "user": {}, "args": ["redis-server", "--bind" "0.0.0.0"], "env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM=xterm"], "cwd": "/", "capabilities": ["CAP_AUDIT_WRITE" "CAP_KILL", "CAP_NET_BIND_SERVICE"], "rlimits": [{"type": "RLIMIT_NOFILE", "hard": 1024, "soft": 1024}], "noNewPrivileges": true} "root": {"path": "rootfs", "readonly": true}, "hostname": "runc", "mounts": [{"destination": "/ proc", "type": "proc", "source": "proc"}, {"destination": "/ dev" Type: "tmpfs", "source": "tmpfs", "options": ["nosuid", "strictatime", "mode=755", "size=65536k"]}, {"destination": "/ dev/pts" "type": "devpts", "source": "devpts", "options": ["nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"]} {"destination": "/ dev/shm", "type": "tmpfs", "source": "shm", "options": ["nosuid", "noexec", "nodev", "mode=1777" "size=65536k"]}, {"destination": "/ dev/mqueue", "type": "mqueue", "source": "mqueue", "options": ["nosuid", "noexec" "nodev"]}, {"destination": "/ sys", "type": "sysfs", "source": "sysfs", "options": ["nosuid", "noexec", "nodev" "ro"]}, {"destination": "/ sys/fs/cgroup", "type": "cgroup", "source": "cgroup", "options": ["nosuid", "noexec", "nodev" "relatime", "ro"]}], "hooks": {}, "linux": {"resources": {"devices": [{"allow": false "access": "rwm"}]}, "namespaces": [{"type": "pid"}, {"type": "ipc"} {"type": "uts"}, {"type": "mount"}], "devices": null}} finish reading the above Have you mastered how to analyze namespace with runC source code? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report