Skip to content

Commit b224c6d

Browse files
avagingvisor-bot
authored andcommitted
proc: Allow to write into /proc/pid/mem
GDB uses /proc/pid/mem to access memory of the target process. PiperOrigin-RevId: 756972644
1 parent 40988f1 commit b224c6d

File tree

3 files changed

+58
-1
lines changed

3 files changed

+58
-1
lines changed

pkg/sentry/fsimpl/proc/task.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func (fs *filesystem) newTaskInode(ctx context.Context, task *kernel.Task, pidns
7171
"io": fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0400, newIO(task, isThreadGroup)),
7272
"limits": fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0444, &limitsData{task: task}),
7373
"maps": fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0444, &mapsData{task: task}),
74-
"mem": fs.newMemInode(ctx, task, fs.NextIno(), 0400),
74+
"mem": fs.newMemInode(ctx, task, fs.NextIno(), 0600),
7575
"mountinfo": fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0444, &mountInfoData{fs: fs, task: task}),
7676
"mounts": fs.newTaskOwnedInode(ctx, task, fs.NextIno(), 0444, &mountsData{fs: fs, task: task}),
7777
"net": fs.newTaskNetDir(ctx, task),

pkg/sentry/fsimpl/proc/task_files.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,33 @@ func (fd *memFD) Seek(ctx context.Context, offset int64, whence int32) (int64, e
510510
return offset, nil
511511
}
512512

513+
// PWrite implements vfs.FileDescriptionImpl.PWrite.
514+
func (fd *memFD) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts vfs.WriteOptions) (int64, error) {
515+
if src.NumBytes() == 0 {
516+
return 0, nil
517+
}
518+
m, err := getMMIncRef(fd.inode.task)
519+
if err != nil {
520+
return 0, err
521+
}
522+
defer m.DecUsers(ctx)
523+
// Buffer the read data because of MM locks
524+
buf := make([]byte, src.NumBytes())
525+
n, readErr := src.CopyIn(ctx, buf)
526+
if n > 0 {
527+
if n, err := m.CopyOut(ctx, hostarch.Addr(offset), buf[:n], usermem.IOOpts{IgnorePermissions: true}); err != nil {
528+
return 0, linuxerr.EFAULT
529+
} else {
530+
return int64(n), nil
531+
}
532+
}
533+
if readErr != nil {
534+
return 0, linuxerr.EIO
535+
}
536+
return 0, nil
537+
538+
}
539+
513540
// PRead implements vfs.FileDescriptionImpl.PRead.
514541
func (fd *memFD) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts vfs.ReadOptions) (int64, error) {
515542
if dst.NumBytes() == 0 {
@@ -535,6 +562,15 @@ func (fd *memFD) PRead(ctx context.Context, dst usermem.IOSequence, offset int64
535562
return 0, nil
536563
}
537564

565+
// Write implements vfs.FileDescriptionImpl.Write.
566+
func (fd *memFD) Write(ctx context.Context, dst usermem.IOSequence, opts vfs.WriteOptions) (int64, error) {
567+
fd.mu.Lock()
568+
n, err := fd.PWrite(ctx, dst, fd.offset, opts)
569+
fd.offset += n
570+
fd.mu.Unlock()
571+
return n, err
572+
}
573+
538574
// Read implements vfs.FileDescriptionImpl.Read.
539575
func (fd *memFD) Read(ctx context.Context, dst usermem.IOSequence, opts vfs.ReadOptions) (int64, error) {
540576
fd.mu.Lock()

test/syscalls/linux/proc.cc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,27 @@ TEST(ProcPidMem, Read) {
564564
ASSERT_STREQ(input, output);
565565
}
566566

567+
TEST(ProcPidMem, PWrite) {
568+
auto memfd = ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/self/mem", O_RDWR));
569+
char input[] = "hello-world";
570+
char output[sizeof(input)];
571+
ASSERT_THAT(pwrite(memfd.get(), input, sizeof(input),
572+
reinterpret_cast<off_t>(output)),
573+
SyscallSucceedsWithValue(sizeof(input)));
574+
ASSERT_STREQ(input, output);
575+
}
576+
577+
TEST(ProcPidMem, Write) {
578+
auto memfd = ASSERT_NO_ERRNO_AND_VALUE(Open("/proc/self/mem", O_RDWR));
579+
char input[] = "hello-world";
580+
char output[sizeof(input)];
581+
ASSERT_THAT(lseek(memfd.get(), reinterpret_cast<off_t>(output), SEEK_SET),
582+
SyscallSucceedsWithValue(reinterpret_cast<off_t>(output)));
583+
ASSERT_THAT(write(memfd.get(), input, sizeof(input)),
584+
SyscallSucceedsWithValue(sizeof(input)));
585+
ASSERT_STREQ(input, output);
586+
}
587+
567588
// Perform read on an unmapped region.
568589
TEST(ProcPidMem, Unmapped) {
569590
// Strategy: map then unmap, so we have a guaranteed unmapped region

0 commit comments

Comments
 (0)