Skip to content

Commit b8d201e

Browse files
committed
idmap
1 parent 19d8a73 commit b8d201e

File tree

9 files changed

+334
-169
lines changed

9 files changed

+334
-169
lines changed

components/workspacekit/cmd/rings.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,10 @@ var ring1Cmd = &cobra.Command{
275275

276276
var mnts []mnte
277277
switch fsshift {
278+
case api.FSShiftMethod_IDMAPPED:
279+
mnts = append(mnts,
280+
mnte{Target: "/", Source: "/.workspace/mark", Flags: unix.MS_BIND | unix.MS_REC},
281+
)
278282
case api.FSShiftMethod_SHIFTFS:
279283
mnts = append(mnts,
280284
mnte{Target: "/", Source: "/.workspace/mark", FSType: "shiftfs"},

components/ws-daemon-api/go/workspace_daemon.pb.go

Lines changed: 159 additions & 144 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ws-daemon-api/go/workspace_daemon_grpc.pb.go

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ws-daemon-api/typescript/src/workspace_daemon_grpc_pb.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ws-daemon-api/typescript/src/workspace_daemon_pb.d.ts

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ws-daemon-api/typescript/src/workspace_daemon_pb.js

Lines changed: 32 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ws-daemon-api/workspace_daemon.proto

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,9 @@ service WorkspaceInfoService {
6868
rpc WorkspaceInfo(WorkspaceInfoRequest) returns (WorkspaceInfoResponse) {}
6969
}
7070

71-
message PrepareForUserNSRequest {}
71+
message PrepareForUserNSRequest {
72+
int64 userns_pid = 1;
73+
}
7274
message PrepareForUserNSResponse {
7375
FSShiftMethod fs_shift = 1;
7476
// was used for full workspace backup
@@ -82,6 +84,7 @@ enum FSShiftMethod {
8284
SHIFTFS = 0;
8385
// was used for FUSE
8486
reserved 1;
87+
IDMAPPED = 2;
8588
}
8689

8790
message WriteIDMappingResponse {

components/ws-daemon/nsinsider/main.go

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"net"
1111
"net/netip"
1212
"os"
13+
"path/filepath"
14+
"sync"
1315
"time"
1416
"unsafe"
1517

@@ -85,6 +87,87 @@ func main() {
8587
return unix.Mount("none", c.String("target"), "", unix.MS_SHARED, "")
8688
},
8789
},
90+
{
91+
Name: "mount-idmapped-mark",
92+
Usage: "mounts a idmapped mark",
93+
Flags: []cli.Flag{
94+
&cli.StringFlag{
95+
Name: "source",
96+
Required: true,
97+
},
98+
&cli.StringFlag{
99+
Name: "merged",
100+
Required: true,
101+
},
102+
&cli.StringFlag{
103+
Name: "upper",
104+
Required: true,
105+
},
106+
&cli.StringFlag{
107+
Name: "work",
108+
Required: true,
109+
},
110+
&cli.StringFlag{
111+
Name: "userns",
112+
Required: true,
113+
},
114+
},
115+
Action: func(c *cli.Context) error {
116+
target := filepath.Clean(c.String("merged"))
117+
upper := filepath.Clean(c.String("upper"))
118+
work := filepath.Clean(c.String("work"))
119+
source := filepath.Clean(c.String("source"))
120+
userns := filepath.Clean(c.String("userns"))
121+
122+
mappedLower, err := os.MkdirTemp("", "idmapped-mark")
123+
if err != nil {
124+
return xerrors.Errorf("mkdirtemp: %w", err)
125+
}
126+
127+
mappedFD, err := unix.OpenTree(unix.AT_FDCWD, source, unix.OPEN_TREE_CLONE)
128+
if err != nil {
129+
return xerrors.Errorf("opentree: %w", err)
130+
}
131+
var closeOnce sync.Once
132+
closeMappedFD := func() {
133+
closeOnce.Do(func() { unix.Close(mappedFD) })
134+
}
135+
defer closeMappedFD()
136+
137+
usernsFD, err := os.Open(userns)
138+
if err != nil {
139+
return xerrors.Errorf("open(userns): %w", err)
140+
}
141+
defer usernsFD.Close()
142+
err = unix.MountSetattr(mappedFD, "", unix.AT_EMPTY_PATH|unix.AT_RECURSIVE, &unix.MountAttr{
143+
Attr_set: unix.MOUNT_ATTR_IDMAP,
144+
Attr_clr: 0,
145+
Propagation: 0,
146+
Userns_fd: uint64(usernsFD.Fd()),
147+
})
148+
if err != nil {
149+
return xerrors.Errorf("mountsetattr: %w", err)
150+
}
151+
152+
err = unix.MoveMount(mappedFD, "", unix.AT_FDCWD, mappedLower, flagMoveMountFEmptyPath)
153+
if err != nil {
154+
return xerrors.Errorf("moveMount: %w", err)
155+
}
156+
157+
err = unix.Mount("overlay", target, "overlay", 0, fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", mappedLower, upper, work))
158+
if err != nil {
159+
return xerrors.Errorf("mount(overlay): %w", err)
160+
}
161+
162+
closeMappedFD()
163+
err = unix.Unmount(mappedLower, 0)
164+
if err != nil {
165+
return xerrors.Errorf("Unmount(mappedLower): %w", err)
166+
}
167+
168+
return nil
169+
},
170+
},
88171
{
89172
Name: "mount-shiftfs-mark",
90173
Usage: "mounts a shiftfs mark",

components/ws-daemon/pkg/iws/iws.go

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -256,30 +256,56 @@ func (wbs *InWorkspaceServiceServer) PrepareForUserNS(ctx context.Context, req *
256256

257257
mountpoint := filepath.Join(wbs.Session.ServiceLocNode, "mark")
258258

259-
// We cannot use the nsenter syscall here because mount namespaces affect the whole process, not just the current thread.
260-
// That's why we resort to exec'ing "nsenter ... mount ...".
261-
err = nsi.Nsinsider(wbs.Session.InstanceID, int(1), func(c *exec.Cmd) {
262-
c.Args = append(c.Args, "make-shared", "--target", "/")
263-
})
264-
if err != nil {
265-
log.WithField("containerPID", containerPID).WithFields(wbs.Session.OWI()).WithError(err).Error("cannot make container's rootfs shared")
266-
return nil, status.Errorf(codes.Internal, "cannot make container's rootfs shared")
267-
}
259+
switch wbs.FSShift {
260+
case api.FSShiftMethod_SHIFTFS:
261+
// We cannot use the nsenter syscall here because mount namespaces affect the whole process, not just the current thread.
262+
// That's why we resort to exec'ing "nsenter ... mount ...".
263+
err = nsi.Nsinsider(wbs.Session.InstanceID, int(1), func(c *exec.Cmd) {
264+
c.Args = append(c.Args, "make-shared", "--target", "/")
265+
})
266+
if err != nil {
267+
log.WithField("containerPID", containerPID).WithFields(wbs.Session.OWI()).WithError(err).Error("cannot make container's rootfs shared")
268+
return nil, status.Errorf(codes.Internal, "cannot make container's rootfs shared")
269+
}
268270

269-
err = nsi.Nsinsider(wbs.Session.InstanceID, int(1), func(c *exec.Cmd) {
270-
c.Args = append(c.Args, "mount-shiftfs-mark", "--source", rootfs, "--target", mountpoint)
271-
})
272-
if err != nil {
273-
log.WithField("rootfs", rootfs).WithFields(wbs.Session.OWI()).WithField("mountpoint", mountpoint).WithError(err).Error("cannot mount shiftfs mark")
274-
return nil, status.Errorf(codes.Internal, "cannot mount shiftfs mark")
271+
err = nsi.Nsinsider(wbs.Session.InstanceID, int(1), func(c *exec.Cmd) {
272+
c.Args = append(c.Args, "mount-shiftfs-mark", "--source", rootfs, "--target", mountpoint)
273+
})
274+
if err != nil {
275+
log.WithField("rootfs", rootfs).WithFields(wbs.Session.OWI()).WithField("mountpoint", mountpoint).WithError(err).Error("cannot mount shiftfs mark")
276+
return nil, status.Errorf(codes.Internal, "cannot mount shiftfs mark")
277+
}
278+
case api.FSShiftMethod_IDMAPPED:
279+
procPID, err := wbs.Uidmapper.findHostPID(containerPID, uint64(req.UsernsPid))
280+
if err != nil {
281+
log.WithError(err).WithField("containerPID", containerPID).WithField("processPID", req.UsernsPid).Error("cannot map in-container PID")
282+
return nil, status.Error(codes.InvalidArgument, "cannot map in-container PID")
283+
}
284+
285+
err = nsi.Nsinsider(wbs.Session.InstanceID, int(1), func(c *exec.Cmd) {
286+
// In case of any change in the user mapping, the next line must be updated.
287+
c.Args = append(c.Args, "mount-idmapped-mark",
288+
"--source", rootfs,
289+
"--merged", filepath.Join(wbs.Session.ServiceLocNode, "mark"),
290+
"--upper", filepath.Join(wbs.Session.ServiceLocNode, "upper"),
291+
"--work", filepath.Join(wbs.Session.ServiceLocNode, "work"),
292+
"--userns", fmt.Sprintf("/proc/%d/ns/user", procPID))
293+
})
294+
if err != nil {
295+
log.WithField("rootfs", rootfs).WithError(err).Error("cannot mount idmapped mark")
296+
return nil, status.Errorf(codes.Internal, "cannot mount idmapped mark")
297+
}
298+
default:
299+
log.WithField("fsshift", wbs.FSShift).Error("unknown fs shift")
300+
return nil, status.Errorf(codes.FailedPrecondition, "unknown fs shift")
275301
}
276302

277303
if err := wbs.createWorkspaceCgroup(ctx, wscontainerID); err != nil {
278304
return nil, err
279305
}
280306

281307
return &api.PrepareForUserNSResponse{
282-
FsShift: api.FSShiftMethod_SHIFTFS,
308+
FsShift: wbs.FSShift,
283309
}, nil
284310
}
285311

0 commit comments

Comments
 (0)