| package mountopts | |
| import ( | |
| "golang.org/x/sys/unix" | |
| ) | |
| // UnprivilegedMountFlags gets the set of mount flags that are set on the mount that contains the given | |
| // path and are locked by CL_UNPRIVILEGED. This is necessary to ensure that | |
| // bind-mounting "with options" will not fail with user namespaces, due to | |
| // kernel restrictions that require user namespace mounts to preserve | |
| // CL_UNPRIVILEGED locked flags. | |
| // | |
| // TODO: Move to github.com/moby/sys/mount, and update BuildKit copy of this code as well (https://github.com/moby/buildkit/blob/v0.13.0/util/rootless/mountopts/mountopts_linux.go#L11-L18) | |
| func UnprivilegedMountFlags(path string) ([]string, error) { | |
| var statfs unix.Statfs_t | |
| if err := unix.Statfs(path, &statfs); err != nil { | |
| return nil, err | |
| } | |
| // The set of keys come from https://github.com/torvalds/linux/blob/v4.13/fs/namespace.c#L1034-L1048. | |
| unprivilegedFlags := map[uint64]string{ | |
| unix.MS_RDONLY: "ro", | |
| unix.MS_NODEV: "nodev", | |
| unix.MS_NOEXEC: "noexec", | |
| unix.MS_NOSUID: "nosuid", | |
| unix.MS_NOATIME: "noatime", | |
| unix.MS_RELATIME: "relatime", | |
| unix.MS_NODIRATIME: "nodiratime", | |
| } | |
| var flags []string | |
| for mask, flag := range unprivilegedFlags { | |
| if uint64(statfs.Flags)&mask == mask { | |
| flags = append(flags, flag) | |
| } | |
| } | |
| return flags, nil | |
| } |