Implement Read in gvisor verity fs
Read is implemented by PRead, with offset obtained from Seek. PiperOrigin-RevId: 338718587
This commit is contained in:
parent
6ee3520b61
commit
39e214090b
|
@ -499,6 +499,10 @@ type fileDescription struct {
|
|||
// directory that contains the current file/directory. This is only used
|
||||
// if allowRuntimeEnable is set to true.
|
||||
parentMerkleWriter *vfs.FileDescription
|
||||
|
||||
// off is the file offset. off is protected by mu.
|
||||
mu sync.Mutex `state:"nosave"`
|
||||
off int64
|
||||
}
|
||||
|
||||
// Release implements vfs.FileDescriptionImpl.Release.
|
||||
|
@ -738,6 +742,16 @@ func (fd *fileDescription) Ioctl(ctx context.Context, uio usermem.IO, args arch.
|
|||
}
|
||||
}
|
||||
|
||||
// Read implements vfs.FileDescriptionImpl.Read.
|
||||
func (fd *fileDescription) Read(ctx context.Context, dst usermem.IOSequence, opts vfs.ReadOptions) (int64, error) {
|
||||
// Implement Read with PRead by setting offset.
|
||||
fd.mu.Lock()
|
||||
n, err := fd.PRead(ctx, dst, fd.off, opts)
|
||||
fd.off += n
|
||||
fd.mu.Unlock()
|
||||
return n, err
|
||||
}
|
||||
|
||||
// PRead implements vfs.FileDescriptionImpl.PRead.
|
||||
func (fd *fileDescription) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts vfs.ReadOptions) (int64, error) {
|
||||
// No need to verify if the file is not enabled yet in
|
||||
|
|
|
@ -180,9 +180,9 @@ func TestOpen(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestUnmodifiedFileSucceeds ensures that read from an untouched verity file
|
||||
// succeeds after enabling verity for it.
|
||||
func TestReadUnmodifiedFileSucceeds(t *testing.T) {
|
||||
// TestPReadUnmodifiedFileSucceeds ensures that pread from an untouched verity
|
||||
// file succeeds after enabling verity for it.
|
||||
func TestPReadUnmodifiedFileSucceeds(t *testing.T) {
|
||||
ctx := contexttest.Context(t)
|
||||
vfsObj, root, err := newVerityRoot(ctx, t)
|
||||
if err != nil {
|
||||
|
@ -213,6 +213,39 @@ func TestReadUnmodifiedFileSucceeds(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestReadUnmodifiedFileSucceeds ensures that read from an untouched verity
|
||||
// file succeeds after enabling verity for it.
|
||||
func TestReadUnmodifiedFileSucceeds(t *testing.T) {
|
||||
ctx := contexttest.Context(t)
|
||||
vfsObj, root, err := newVerityRoot(ctx, t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
|
||||
filename := "verity-test-file"
|
||||
fd, size, err := newFileFD(ctx, vfsObj, root, filename, 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("newFileFD: %v", err)
|
||||
}
|
||||
|
||||
// Enable verity on the file and confirm a normal read succeeds.
|
||||
var args arch.SyscallArguments
|
||||
args[1] = arch.SyscallArgument{Value: linux.FS_IOC_ENABLE_VERITY}
|
||||
if _, err := fd.Ioctl(ctx, nil /* uio */, args); err != nil {
|
||||
t.Fatalf("Ioctl: %v", err)
|
||||
}
|
||||
|
||||
buf := make([]byte, size)
|
||||
n, err := fd.Read(ctx, usermem.BytesIOSequence(buf), vfs.ReadOptions{})
|
||||
if err != nil && err != io.EOF {
|
||||
t.Fatalf("fd.Read: %v", err)
|
||||
}
|
||||
|
||||
if n != int64(size) {
|
||||
t.Errorf("fd.PRead got read length %d, want %d", n, size)
|
||||
}
|
||||
}
|
||||
|
||||
// TestReopenUnmodifiedFileSucceeds ensures that reopen an untouched verity file
|
||||
// succeeds after enabling verity for it.
|
||||
func TestReopenUnmodifiedFileSucceeds(t *testing.T) {
|
||||
|
@ -248,8 +281,9 @@ func TestReopenUnmodifiedFileSucceeds(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestModifiedFileFails ensures that read from a modified verity file fails.
|
||||
func TestModifiedFileFails(t *testing.T) {
|
||||
// TestPReadModifiedFileFails ensures that read from a modified verity file
|
||||
// fails.
|
||||
func TestPReadModifiedFileFails(t *testing.T) {
|
||||
ctx := contexttest.Context(t)
|
||||
vfsObj, root, err := newVerityRoot(ctx, t)
|
||||
if err != nil {
|
||||
|
@ -289,7 +323,53 @@ func TestModifiedFileFails(t *testing.T) {
|
|||
// Confirm that read from the modified file fails.
|
||||
buf := make([]byte, size)
|
||||
if _, err := fd.PRead(ctx, usermem.BytesIOSequence(buf), 0 /* offset */, vfs.ReadOptions{}); err == nil {
|
||||
t.Fatalf("fd.PRead succeeded with modified file")
|
||||
t.Fatalf("fd.PRead succeeded, expected failure")
|
||||
}
|
||||
}
|
||||
|
||||
// TestReadModifiedFileFails ensures that read from a modified verity file
|
||||
// fails.
|
||||
func TestReadModifiedFileFails(t *testing.T) {
|
||||
ctx := contexttest.Context(t)
|
||||
vfsObj, root, err := newVerityRoot(ctx, t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
|
||||
filename := "verity-test-file"
|
||||
fd, size, err := newFileFD(ctx, vfsObj, root, filename, 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("newFileFD: %v", err)
|
||||
}
|
||||
|
||||
// Enable verity on the file.
|
||||
var args arch.SyscallArguments
|
||||
args[1] = arch.SyscallArgument{Value: linux.FS_IOC_ENABLE_VERITY}
|
||||
if _, err := fd.Ioctl(ctx, nil /* uio */, args); err != nil {
|
||||
t.Fatalf("Ioctl: %v", err)
|
||||
}
|
||||
|
||||
// Open a new lowerFD that's read/writable.
|
||||
lowerVD := fd.Impl().(*fileDescription).d.lowerVD
|
||||
|
||||
lowerFD, err := vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: lowerVD,
|
||||
Start: lowerVD,
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDWR,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("OpenAt: %v", err)
|
||||
}
|
||||
|
||||
if err := corruptRandomBit(ctx, lowerFD, size); err != nil {
|
||||
t.Fatalf("corruptRandomBit: %v", err)
|
||||
}
|
||||
|
||||
// Confirm that read from the modified file fails.
|
||||
buf := make([]byte, size)
|
||||
if _, err := fd.Read(ctx, usermem.BytesIOSequence(buf), vfs.ReadOptions{}); err == nil {
|
||||
t.Fatalf("fd.Read succeeded, expected failure")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue