Skip to content

Commit 3cf3384

Browse files
milantracygvisor-bot
authored andcommitted
Return a task image's file capability when the image is loaded to be executed.
PiperOrigin-RevId: 613732844
1 parent be79481 commit 3cf3384

File tree

4 files changed

+54
-18
lines changed

4 files changed

+54
-18
lines changed

pkg/sentry/kernel/task_image.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ type TaskImage struct {
5050

5151
// st is the task's syscall table.
5252
st *SyscallTable `state:".(syscallTableInfo)"`
53+
54+
// fileCaps is the image's extended attribute named security.capability.
55+
fileCaps string
56+
}
57+
58+
// FileCaps return the task image's security.capability extended attribute.
59+
func (image *TaskImage) FileCaps() string {
60+
return image.fileCaps
5361
}
5462

5563
// release releases all resources held by the TaskImage. release is called by
@@ -142,13 +150,13 @@ func (k *Kernel) LoadTaskImage(ctx context.Context, args loader.LoadArgs) (*Task
142150
defer m.DecUsers(ctx)
143151
args.MemoryManager = m
144152

145-
os, ac, name, err := loader.Load(ctx, args, k.extraAuxv, k.vdso)
153+
info, err := loader.Load(ctx, args, k.extraAuxv, k.vdso)
146154
if err != nil {
147155
return nil, err
148156
}
149157

150158
// Lookup our new syscall table.
151-
st, ok := LookupSyscallTable(os, ac.Arch())
159+
st, ok := LookupSyscallTable(info.OS, info.Arch.Arch())
152160
if !ok {
153161
// No syscall table found. This means that the ELF binary does not match
154162
// the architecture.
@@ -159,10 +167,11 @@ func (k *Kernel) LoadTaskImage(ctx context.Context, args loader.LoadArgs) (*Task
159167
panic("Failed to increment users count on new MM")
160168
}
161169
return &TaskImage{
162-
Name: name,
163-
Arch: ac,
170+
Name: info.Name,
171+
Arch: info.Arch,
164172
MemoryManager: m,
165173
fu: k.futexes.Fork(),
166174
st: st,
175+
fileCaps: info.FileCaps,
167176
}, nil
168177
}

pkg/sentry/loader/loader.go

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ import (
3838
"gvisor.dev/gvisor/pkg/usermem"
3939
)
4040

41+
const (
42+
securityCapability = linux.XATTR_SECURITY_PREFIX + "capability"
43+
)
44+
4145
// LoadArgs holds specifications for an executable file to be loaded.
4246
type LoadArgs struct {
4347
// MemoryManager is the memory manager to load the executable into.
@@ -236,6 +240,18 @@ func loadExecutable(ctx context.Context, args LoadArgs) (loadedELF, *arch.Contex
236240
return loadedELF{}, nil, nil, nil, linuxerr.ELOOP
237241
}
238242

243+
// ImageInfo represents the information for the loaded image.
244+
type ImageInfo struct {
245+
// The target operating system of the image.
246+
OS abi.OS
247+
// AMD64 context.
248+
Arch *arch.Context64
249+
// The base name of the binary.
250+
Name string
251+
// The binary's file capability.
252+
FileCaps string
253+
}
254+
239255
// Load loads args.File into a MemoryManager. If args.File is nil, the path
240256
// args.Filename is resolved and loaded instead.
241257
//
@@ -245,48 +261,55 @@ func loadExecutable(ctx context.Context, args LoadArgs) (loadedELF, *arch.Contex
245261
// Preconditions:
246262
// - The Task MemoryManager is empty.
247263
// - Load is called on the Task goroutine.
248-
func Load(ctx context.Context, args LoadArgs, extraAuxv []arch.AuxEntry, vdso *VDSO) (abi.OS, *arch.Context64, string, *syserr.Error) {
264+
func Load(ctx context.Context, args LoadArgs, extraAuxv []arch.AuxEntry, vdso *VDSO) (ImageInfo, *syserr.Error) {
249265
// Load the executable itself.
250266
loaded, ac, file, newArgv, err := loadExecutable(ctx, args)
251267
if err != nil {
252-
return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("failed to load %s: %v", args.Filename, err), syserr.FromError(err).ToLinux())
268+
return ImageInfo{}, syserr.NewDynamic(fmt.Sprintf("failed to load %s: %v", args.Filename, err), syserr.FromError(err).ToLinux())
253269
}
254270
defer file.DecRef(ctx)
271+
xattr, err := file.GetXattr(ctx, &vfs.GetXattrOptions{Name: securityCapability, Size: linux.XATTR_CAPS_SZ_3})
272+
switch {
273+
case linuxerr.Equals(linuxerr.ENODATA, err), linuxerr.Equals(linuxerr.ENOTSUP, err):
274+
xattr = ""
275+
case err != nil:
276+
return ImageInfo{}, syserr.NewDynamic(fmt.Sprintf("failed to read file capabilities of %s: %v", args.Filename, err), syserr.FromError(err).ToLinux())
277+
}
255278

256279
// Load the VDSO.
257280
vdsoAddr, err := loadVDSO(ctx, args.MemoryManager, vdso, loaded)
258281
if err != nil {
259-
return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("error loading VDSO: %v", err), syserr.FromError(err).ToLinux())
282+
return ImageInfo{}, syserr.NewDynamic(fmt.Sprintf("error loading VDSO: %v", err), syserr.FromError(err).ToLinux())
260283
}
261284

262285
// Setup the heap. brk starts at the next page after the end of the
263286
// executable. Userspace can assume that the remainder of the page after
264287
// loaded.end is available for its use.
265288
e, ok := loaded.end.RoundUp()
266289
if !ok {
267-
return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("brk overflows: %#x", loaded.end), errno.ENOEXEC)
290+
return ImageInfo{}, syserr.NewDynamic(fmt.Sprintf("brk overflows: %#x", loaded.end), errno.ENOEXEC)
268291
}
269292
args.MemoryManager.BrkSetup(ctx, e)
270293

271294
// Allocate our stack.
272295
stack, err := allocStack(ctx, args.MemoryManager, ac)
273296
if err != nil {
274-
return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("Failed to allocate stack: %v", err), syserr.FromError(err).ToLinux())
297+
return ImageInfo{}, syserr.NewDynamic(fmt.Sprintf("Failed to allocate stack: %v", err), syserr.FromError(err).ToLinux())
275298
}
276299

277300
// Push the original filename to the stack, for AT_EXECFN.
278301
if _, err := stack.PushNullTerminatedByteSlice([]byte(args.Filename)); err != nil {
279-
return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("Failed to push exec filename: %v", err), syserr.FromError(err).ToLinux())
302+
return ImageInfo{}, syserr.NewDynamic(fmt.Sprintf("Failed to push exec filename: %v", err), syserr.FromError(err).ToLinux())
280303
}
281304
execfn := stack.Bottom
282305

283306
// Push 16 random bytes on the stack which AT_RANDOM will point to.
284307
var b [16]byte
285308
if _, err := rand.Read(b[:]); err != nil {
286-
return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("Failed to read random bytes: %v", err), syserr.FromError(err).ToLinux())
309+
return ImageInfo{}, syserr.NewDynamic(fmt.Sprintf("Failed to read random bytes: %v", err), syserr.FromError(err).ToLinux())
287310
}
288311
if _, err = stack.PushNullTerminatedByteSlice(b[:]); err != nil {
289-
return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("Failed to push random bytes: %v", err), syserr.FromError(err).ToLinux())
312+
return ImageInfo{}, syserr.NewDynamic(fmt.Sprintf("Failed to push random bytes: %v", err), syserr.FromError(err).ToLinux())
290313
}
291314
random := stack.Bottom
292315

@@ -311,7 +334,7 @@ func Load(ctx context.Context, args LoadArgs, extraAuxv []arch.AuxEntry, vdso *V
311334

312335
sl, err := stack.Load(newArgv, args.Envv, auxv)
313336
if err != nil {
314-
return 0, nil, "", syserr.NewDynamic(fmt.Sprintf("Failed to load stack: %v", err), syserr.FromError(err).ToLinux())
337+
return ImageInfo{}, syserr.NewDynamic(fmt.Sprintf("Failed to load stack: %v", err), syserr.FromError(err).ToLinux())
315338
}
316339

317340
m := args.MemoryManager
@@ -331,5 +354,10 @@ func Load(ctx context.Context, args LoadArgs, extraAuxv []arch.AuxEntry, vdso *V
331354
name = name[:linux.TASK_COMM_LEN-1]
332355
}
333356

334-
return loaded.os, ac, name, nil
357+
return ImageInfo{
358+
OS: loaded.os,
359+
Arch: ac,
360+
Name: name,
361+
FileCaps: xattr,
362+
}, nil
335363
}

pkg/sentry/vfs/permissions.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ func CheckXattrPermissions(creds *auth.Credentials, ats AccessTypes, mode linux.
325325
}
326326
case strings.HasPrefix(name, linux.XATTR_SECURITY_PREFIX):
327327
if ats.MayRead() {
328-
return linuxerr.ENODATA
328+
return nil
329329
}
330330
return linuxerr.EOPNOTSUPP
331331
}

test/syscalls/linux/xattr.cc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ namespace testing {
3939
namespace {
4040

4141
using ::gvisor::testing::IsTmpfs;
42+
using ::testing::AnyOf;
4243

4344
class XattrTest : public FileTest {};
4445

@@ -112,11 +113,9 @@ TEST_F(XattrTest, SecurityCapacityXattr) {
112113
const std::string val = "";
113114
EXPECT_THAT(lsetxattr(path, name, &val, val.size(), 0),
114115
SyscallFailsWithErrno(EOPNOTSUPP));
115-
116116
int buf = 0;
117117
EXPECT_THAT(lgetxattr(path, name, &buf, /*size=*/128),
118-
SyscallFailsWithErrno(ENODATA));
119-
118+
SyscallFailsWithErrno(AnyOf(ENODATA, EOPNOTSUPP)));
120119
EXPECT_THAT(lremovexattr(path, name), SyscallFailsWithErrno(EOPNOTSUPP));
121120
}
122121

0 commit comments

Comments
 (0)