Pass hashing algorithms in verity fs opts
PiperOrigin-RevId: 340275942
This commit is contained in:
parent
2eb3ee586b
commit
ed4f857343
|
@ -276,9 +276,9 @@ func (fs *filesystem) verifyChild(ctx context.Context, parent *dentry, child *de
|
|||
UID: parentStat.UID,
|
||||
GID: parentStat.GID,
|
||||
//TODO(b/156980949): Support passing other hash algorithms.
|
||||
HashAlgorithms: linux.FS_VERITY_HASH_ALG_SHA256,
|
||||
HashAlgorithms: fs.alg.toLinuxHashAlg(),
|
||||
ReadOffset: int64(offset),
|
||||
ReadSize: int64(merkletree.DigestSize(linux.FS_VERITY_HASH_ALG_SHA256)),
|
||||
ReadSize: int64(merkletree.DigestSize(fs.alg.toLinuxHashAlg())),
|
||||
Expected: parent.hash,
|
||||
DataAndTreeInSameFile: true,
|
||||
}); err != nil && err != io.EOF {
|
||||
|
@ -352,7 +352,7 @@ func (fs *filesystem) verifyStat(ctx context.Context, d *dentry, stat linux.Stat
|
|||
UID: stat.UID,
|
||||
GID: stat.GID,
|
||||
//TODO(b/156980949): Support passing other hash algorithms.
|
||||
HashAlgorithms: linux.FS_VERITY_HASH_ALG_SHA256,
|
||||
HashAlgorithms: fs.alg.toLinuxHashAlg(),
|
||||
ReadOffset: 0,
|
||||
// Set read size to 0 so only the metadata is verified.
|
||||
ReadSize: 0,
|
||||
|
|
|
@ -79,6 +79,27 @@ var (
|
|||
verityMu sync.RWMutex
|
||||
)
|
||||
|
||||
// HashAlgorithm is a type specifying the algorithm used to hash the file
|
||||
// content.
|
||||
type HashAlgorithm int
|
||||
|
||||
// Currently supported hashing algorithms include SHA256 and SHA512.
|
||||
const (
|
||||
SHA256 HashAlgorithm = iota
|
||||
SHA512
|
||||
)
|
||||
|
||||
func (alg HashAlgorithm) toLinuxHashAlg() int {
|
||||
switch alg {
|
||||
case SHA256:
|
||||
return linux.FS_VERITY_HASH_ALG_SHA256
|
||||
case SHA512:
|
||||
return linux.FS_VERITY_HASH_ALG_SHA512
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// FilesystemType implements vfs.FilesystemType.
|
||||
//
|
||||
// +stateify savable
|
||||
|
@ -108,6 +129,10 @@ type filesystem struct {
|
|||
// stores the root hash of the whole file system in bytes.
|
||||
rootDentry *dentry
|
||||
|
||||
// alg is the algorithms used to hash the files in the verity file
|
||||
// system.
|
||||
alg HashAlgorithm
|
||||
|
||||
// renameMu synchronizes renaming with non-renaming operations in order
|
||||
// to ensure consistent lock ordering between dentry.dirMu in different
|
||||
// dentries.
|
||||
|
@ -136,6 +161,10 @@ type InternalFilesystemOptions struct {
|
|||
// LowerName is the name of the filesystem wrapped by verity fs.
|
||||
LowerName string
|
||||
|
||||
// Alg is the algorithms used to hash the files in the verity file
|
||||
// system.
|
||||
Alg HashAlgorithm
|
||||
|
||||
// RootHash is the root hash of the overall verity file system.
|
||||
RootHash []byte
|
||||
|
||||
|
@ -194,6 +223,7 @@ func (fstype FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
|||
|
||||
fs := &filesystem{
|
||||
creds: creds.Fork(),
|
||||
alg: iopts.Alg,
|
||||
lowerMount: mnt,
|
||||
allowRuntimeEnable: iopts.AllowRuntimeEnable,
|
||||
}
|
||||
|
@ -627,7 +657,7 @@ func (fd *fileDescription) generateMerkle(ctx context.Context) ([]byte, uint64,
|
|||
TreeReader: &merkleReader,
|
||||
TreeWriter: &merkleWriter,
|
||||
//TODO(b/156980949): Support passing other hash algorithms.
|
||||
HashAlgorithms: linux.FS_VERITY_HASH_ALG_SHA256,
|
||||
HashAlgorithms: fd.d.fs.alg.toLinuxHashAlg(),
|
||||
}
|
||||
|
||||
switch atomic.LoadUint32(&fd.d.mode) & linux.S_IFMT {
|
||||
|
@ -873,7 +903,7 @@ func (fd *fileDescription) PRead(ctx context.Context, dst usermem.IOSequence, of
|
|||
UID: fd.d.uid,
|
||||
GID: fd.d.gid,
|
||||
//TODO(b/156980949): Support passing other hash algorithms.
|
||||
HashAlgorithms: linux.FS_VERITY_HASH_ALG_SHA256,
|
||||
HashAlgorithms: fd.d.fs.alg.toLinuxHashAlg(),
|
||||
ReadOffset: offset,
|
||||
ReadSize: dst.NumBytes(),
|
||||
Expected: fd.d.hash,
|
||||
|
|
|
@ -43,7 +43,7 @@ const maxDataSize = 100000
|
|||
// newVerityRoot creates a new verity mount, and returns the root. The
|
||||
// underlying file system is tmpfs. If the error is not nil, then cleanup
|
||||
// should be called when the root is no longer needed.
|
||||
func newVerityRoot(t *testing.T) (*vfs.VirtualFilesystem, vfs.VirtualDentry, *kernel.Task, error) {
|
||||
func newVerityRoot(t *testing.T, hashAlg HashAlgorithm) (*vfs.VirtualFilesystem, vfs.VirtualDentry, *kernel.Task, error) {
|
||||
k, err := testutil.Boot()
|
||||
if err != nil {
|
||||
t.Fatalf("testutil.Boot: %v", err)
|
||||
|
@ -70,6 +70,7 @@ func newVerityRoot(t *testing.T) (*vfs.VirtualFilesystem, vfs.VirtualDentry, *ke
|
|||
InternalData: InternalFilesystemOptions{
|
||||
RootMerkleFileName: rootMerkleFilename,
|
||||
LowerName: "tmpfs",
|
||||
Alg: hashAlg,
|
||||
AllowRuntimeEnable: true,
|
||||
NoCrashOnVerificationFailure: true,
|
||||
},
|
||||
|
@ -161,280 +162,296 @@ func corruptRandomBit(ctx context.Context, fd *vfs.FileDescription, size int) er
|
|||
return nil
|
||||
}
|
||||
|
||||
var hashAlgs = []HashAlgorithm{SHA256, SHA512}
|
||||
|
||||
// TestOpen ensures that when a file is created, the corresponding Merkle tree
|
||||
// file and the root Merkle tree file exist.
|
||||
func TestOpen(t *testing.T) {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
for _, alg := range hashAlgs {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t, alg)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
|
||||
filename := "verity-test-file"
|
||||
if _, _, err := newFileFD(ctx, vfsObj, root, filename, 0644); err != nil {
|
||||
t.Fatalf("newFileFD: %v", err)
|
||||
}
|
||||
filename := "verity-test-file"
|
||||
if _, _, err := newFileFD(ctx, vfsObj, root, filename, 0644); err != nil {
|
||||
t.Fatalf("newFileFD: %v", err)
|
||||
}
|
||||
|
||||
// Ensure that the corresponding Merkle tree file is created.
|
||||
lowerRoot := root.Dentry().Impl().(*dentry).lowerVD
|
||||
if _, err = vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: lowerRoot,
|
||||
Start: lowerRoot,
|
||||
Path: fspath.Parse(merklePrefix + filename),
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
}); err != nil {
|
||||
t.Errorf("OpenAt Merkle tree file %s: %v", merklePrefix+filename, err)
|
||||
}
|
||||
// Ensure that the corresponding Merkle tree file is created.
|
||||
lowerRoot := root.Dentry().Impl().(*dentry).lowerVD
|
||||
if _, err = vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: lowerRoot,
|
||||
Start: lowerRoot,
|
||||
Path: fspath.Parse(merklePrefix + filename),
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
}); err != nil {
|
||||
t.Errorf("OpenAt Merkle tree file %s: %v", merklePrefix+filename, err)
|
||||
}
|
||||
|
||||
// Ensure the root merkle tree file is created.
|
||||
if _, err = vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: lowerRoot,
|
||||
Start: lowerRoot,
|
||||
Path: fspath.Parse(merklePrefix + rootMerkleFilename),
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
}); err != nil {
|
||||
t.Errorf("OpenAt root Merkle tree file %s: %v", merklePrefix+rootMerkleFilename, err)
|
||||
// Ensure the root merkle tree file is created.
|
||||
if _, err = vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: lowerRoot,
|
||||
Start: lowerRoot,
|
||||
Path: fspath.Parse(merklePrefix + rootMerkleFilename),
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
}); err != nil {
|
||||
t.Errorf("OpenAt root Merkle tree file %s: %v", merklePrefix+rootMerkleFilename, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestPReadUnmodifiedFileSucceeds ensures that pread from an untouched verity
|
||||
// file succeeds after enabling verity for it.
|
||||
func TestPReadUnmodifiedFileSucceeds(t *testing.T) {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
for _, alg := range hashAlgs {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t, alg)
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
// 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.PRead(ctx, usermem.BytesIOSequence(buf), 0 /* offset */, vfs.ReadOptions{})
|
||||
if err != nil && err != io.EOF {
|
||||
t.Fatalf("fd.PRead: %v", err)
|
||||
}
|
||||
buf := make([]byte, size)
|
||||
n, err := fd.PRead(ctx, usermem.BytesIOSequence(buf), 0 /* offset */, vfs.ReadOptions{})
|
||||
if err != nil && err != io.EOF {
|
||||
t.Fatalf("fd.PRead: %v", err)
|
||||
}
|
||||
|
||||
if n != int64(size) {
|
||||
t.Errorf("fd.PRead got read length %d, want %d", n, size)
|
||||
if n != int64(size) {
|
||||
t.Errorf("fd.PRead got read length %d, want %d", n, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestReadUnmodifiedFileSucceeds ensures that read from an untouched verity
|
||||
// file succeeds after enabling verity for it.
|
||||
func TestReadUnmodifiedFileSucceeds(t *testing.T) {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
for _, alg := range hashAlgs {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t, alg)
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
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)
|
||||
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) {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
for _, alg := range hashAlgs {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t, alg)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
|
||||
filename := "verity-test-file"
|
||||
fd, _, err := newFileFD(ctx, vfsObj, root, filename, 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("newFileFD: %v", err)
|
||||
}
|
||||
filename := "verity-test-file"
|
||||
fd, _, err := newFileFD(ctx, vfsObj, root, filename, 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("newFileFD: %v", err)
|
||||
}
|
||||
|
||||
// Enable verity on the file and confirms 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)
|
||||
}
|
||||
// Enable verity on the file and confirms 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)
|
||||
}
|
||||
|
||||
// Ensure reopening the verity enabled file succeeds.
|
||||
if _, err = vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: root,
|
||||
Start: root,
|
||||
Path: fspath.Parse(filename),
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
Mode: linux.ModeRegular,
|
||||
}); err != nil {
|
||||
t.Errorf("reopen enabled file failed: %v", err)
|
||||
// Ensure reopening the verity enabled file succeeds.
|
||||
if _, err = vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: root,
|
||||
Start: root,
|
||||
Path: fspath.Parse(filename),
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
Mode: linux.ModeRegular,
|
||||
}); err != nil {
|
||||
t.Errorf("reopen enabled file failed: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestPReadModifiedFileFails ensures that read from a modified verity file
|
||||
// fails.
|
||||
func TestPReadModifiedFileFails(t *testing.T) {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
for _, alg := range hashAlgs {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t, alg)
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
// 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
|
||||
// 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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
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.PRead(ctx, usermem.BytesIOSequence(buf), 0 /* offset */, vfs.ReadOptions{}); err == nil {
|
||||
t.Fatalf("fd.PRead succeeded, expected failure")
|
||||
// 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, expected failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestReadModifiedFileFails ensures that read from a modified verity file
|
||||
// fails.
|
||||
func TestReadModifiedFileFails(t *testing.T) {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
for _, alg := range hashAlgs {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t, alg)
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
// 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
|
||||
// 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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
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")
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestModifiedMerkleFails ensures that read from a verity file fails if the
|
||||
// corresponding Merkle tree file is modified.
|
||||
func TestModifiedMerkleFails(t *testing.T) {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
for _, alg := range hashAlgs {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t, alg)
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
// 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 lowerMerkleFD that's read/writable.
|
||||
lowerMerkleVD := fd.Impl().(*fileDescription).d.lowerMerkleVD
|
||||
// Open a new lowerMerkleFD that's read/writable.
|
||||
lowerMerkleVD := fd.Impl().(*fileDescription).d.lowerMerkleVD
|
||||
|
||||
lowerMerkleFD, err := vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: lowerMerkleVD,
|
||||
Start: lowerMerkleVD,
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDWR,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("OpenAt: %v", err)
|
||||
}
|
||||
lowerMerkleFD, err := vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: lowerMerkleVD,
|
||||
Start: lowerMerkleVD,
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDWR,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("OpenAt: %v", err)
|
||||
}
|
||||
|
||||
// Flip a random bit in the Merkle tree file.
|
||||
stat, err := lowerMerkleFD.Stat(ctx, vfs.StatOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("stat: %v", err)
|
||||
}
|
||||
merkleSize := int(stat.Size)
|
||||
if err := corruptRandomBit(ctx, lowerMerkleFD, merkleSize); err != nil {
|
||||
t.Fatalf("corruptRandomBit: %v", err)
|
||||
}
|
||||
// Flip a random bit in the Merkle tree file.
|
||||
stat, err := lowerMerkleFD.Stat(ctx, vfs.StatOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("stat: %v", err)
|
||||
}
|
||||
merkleSize := int(stat.Size)
|
||||
if err := corruptRandomBit(ctx, lowerMerkleFD, merkleSize); err != nil {
|
||||
t.Fatalf("corruptRandomBit: %v", err)
|
||||
}
|
||||
|
||||
// Confirm that read from a file with modified Merkle tree fails.
|
||||
buf := make([]byte, size)
|
||||
if _, err := fd.PRead(ctx, usermem.BytesIOSequence(buf), 0 /* offset */, vfs.ReadOptions{}); err == nil {
|
||||
fmt.Println(buf)
|
||||
t.Fatalf("fd.PRead succeeded with modified Merkle file")
|
||||
// Confirm that read from a file with modified Merkle tree fails.
|
||||
buf := make([]byte, size)
|
||||
if _, err := fd.PRead(ctx, usermem.BytesIOSequence(buf), 0 /* offset */, vfs.ReadOptions{}); err == nil {
|
||||
fmt.Println(buf)
|
||||
t.Fatalf("fd.PRead succeeded with modified Merkle file")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -442,140 +459,146 @@ func TestModifiedMerkleFails(t *testing.T) {
|
|||
// verity enabled directory fails if the hashes related to the target file in
|
||||
// the parent Merkle tree file is modified.
|
||||
func TestModifiedParentMerkleFails(t *testing.T) {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
for _, alg := range hashAlgs {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t, alg)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
|
||||
filename := "verity-test-file"
|
||||
fd, _, err := newFileFD(ctx, vfsObj, root, filename, 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("newFileFD: %v", err)
|
||||
}
|
||||
filename := "verity-test-file"
|
||||
fd, _, 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)
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
|
||||
// Enable verity on the parent directory.
|
||||
parentFD, err := vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: root,
|
||||
Start: root,
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("OpenAt: %v", err)
|
||||
}
|
||||
// Enable verity on the parent directory.
|
||||
parentFD, err := vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: root,
|
||||
Start: root,
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("OpenAt: %v", err)
|
||||
}
|
||||
|
||||
if _, err := parentFD.Ioctl(ctx, nil /* uio */, args); err != nil {
|
||||
t.Fatalf("Ioctl: %v", err)
|
||||
}
|
||||
if _, err := parentFD.Ioctl(ctx, nil /* uio */, args); err != nil {
|
||||
t.Fatalf("Ioctl: %v", err)
|
||||
}
|
||||
|
||||
// Open a new lowerMerkleFD that's read/writable.
|
||||
parentLowerMerkleVD := fd.Impl().(*fileDescription).d.parent.lowerMerkleVD
|
||||
// Open a new lowerMerkleFD that's read/writable.
|
||||
parentLowerMerkleVD := fd.Impl().(*fileDescription).d.parent.lowerMerkleVD
|
||||
|
||||
parentLowerMerkleFD, err := vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: parentLowerMerkleVD,
|
||||
Start: parentLowerMerkleVD,
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDWR,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("OpenAt: %v", err)
|
||||
}
|
||||
parentLowerMerkleFD, err := vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: parentLowerMerkleVD,
|
||||
Start: parentLowerMerkleVD,
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDWR,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("OpenAt: %v", err)
|
||||
}
|
||||
|
||||
// Flip a random bit in the parent Merkle tree file.
|
||||
// This parent directory contains only one child, so any random
|
||||
// modification in the parent Merkle tree should cause verification
|
||||
// failure when opening the child file.
|
||||
stat, err := parentLowerMerkleFD.Stat(ctx, vfs.StatOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("stat: %v", err)
|
||||
}
|
||||
parentMerkleSize := int(stat.Size)
|
||||
if err := corruptRandomBit(ctx, parentLowerMerkleFD, parentMerkleSize); err != nil {
|
||||
t.Fatalf("corruptRandomBit: %v", err)
|
||||
}
|
||||
// Flip a random bit in the parent Merkle tree file.
|
||||
// This parent directory contains only one child, so any random
|
||||
// modification in the parent Merkle tree should cause verification
|
||||
// failure when opening the child file.
|
||||
stat, err := parentLowerMerkleFD.Stat(ctx, vfs.StatOptions{})
|
||||
if err != nil {
|
||||
t.Fatalf("stat: %v", err)
|
||||
}
|
||||
parentMerkleSize := int(stat.Size)
|
||||
if err := corruptRandomBit(ctx, parentLowerMerkleFD, parentMerkleSize); err != nil {
|
||||
t.Fatalf("corruptRandomBit: %v", err)
|
||||
}
|
||||
|
||||
parentLowerMerkleFD.DecRef(ctx)
|
||||
parentLowerMerkleFD.DecRef(ctx)
|
||||
|
||||
// Ensure reopening the verity enabled file fails.
|
||||
if _, err = vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: root,
|
||||
Start: root,
|
||||
Path: fspath.Parse(filename),
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
Mode: linux.ModeRegular,
|
||||
}); err == nil {
|
||||
t.Errorf("OpenAt file with modified parent Merkle succeeded")
|
||||
// Ensure reopening the verity enabled file fails.
|
||||
if _, err = vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: root,
|
||||
Start: root,
|
||||
Path: fspath.Parse(filename),
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
Mode: linux.ModeRegular,
|
||||
}); err == nil {
|
||||
t.Errorf("OpenAt file with modified parent Merkle succeeded")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestUnmodifiedStatSucceeds ensures that stat of an untouched verity file
|
||||
// succeeds after enabling verity for it.
|
||||
func TestUnmodifiedStatSucceeds(t *testing.T) {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
for _, alg := range hashAlgs {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t, alg)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
|
||||
filename := "verity-test-file"
|
||||
fd, _, err := newFileFD(ctx, vfsObj, root, filename, 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("newFileFD: %v", err)
|
||||
}
|
||||
filename := "verity-test-file"
|
||||
fd, _, err := newFileFD(ctx, vfsObj, root, filename, 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("newFileFD: %v", err)
|
||||
}
|
||||
|
||||
// Enable verity on the file and confirms stat 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("fd.Ioctl: %v", err)
|
||||
}
|
||||
// Enable verity on the file and confirms stat 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("fd.Ioctl: %v", err)
|
||||
}
|
||||
|
||||
if _, err := fd.Stat(ctx, vfs.StatOptions{}); err != nil {
|
||||
t.Errorf("fd.Stat: %v", err)
|
||||
if _, err := fd.Stat(ctx, vfs.StatOptions{}); err != nil {
|
||||
t.Errorf("fd.Stat: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestModifiedStatFails checks that getting stat for a file with modified stat
|
||||
// should fail.
|
||||
func TestModifiedStatFails(t *testing.T) {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
for _, alg := range hashAlgs {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t, alg)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
|
||||
filename := "verity-test-file"
|
||||
fd, _, err := newFileFD(ctx, vfsObj, root, filename, 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("newFileFD: %v", err)
|
||||
}
|
||||
filename := "verity-test-file"
|
||||
fd, _, 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("fd.Ioctl: %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("fd.Ioctl: %v", err)
|
||||
}
|
||||
|
||||
lowerFD := fd.Impl().(*fileDescription).lowerFD
|
||||
// Change the stat of the underlying file, and check that stat fails.
|
||||
if err := lowerFD.SetStat(ctx, vfs.SetStatOptions{
|
||||
Stat: linux.Statx{
|
||||
Mask: uint32(linux.STATX_MODE),
|
||||
Mode: 0777,
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatalf("lowerFD.SetStat: %v", err)
|
||||
}
|
||||
lowerFD := fd.Impl().(*fileDescription).lowerFD
|
||||
// Change the stat of the underlying file, and check that stat fails.
|
||||
if err := lowerFD.SetStat(ctx, vfs.SetStatOptions{
|
||||
Stat: linux.Statx{
|
||||
Mask: uint32(linux.STATX_MODE),
|
||||
Mode: 0777,
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatalf("lowerFD.SetStat: %v", err)
|
||||
}
|
||||
|
||||
if _, err := fd.Stat(ctx, vfs.StatOptions{}); err == nil {
|
||||
t.Errorf("fd.Stat succeeded when it should fail")
|
||||
if _, err := fd.Stat(ctx, vfs.StatOptions{}); err == nil {
|
||||
t.Errorf("fd.Stat succeeded when it should fail")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -616,84 +639,86 @@ func TestOpenDeletedFileFails(t *testing.T) {
|
|||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("remove:%t", tc.remove), func(t *testing.T) {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
for _, alg := range hashAlgs {
|
||||
vfsObj, root, ctx, err := newVerityRoot(t, alg)
|
||||
if err != nil {
|
||||
t.Fatalf("newVerityRoot: %v", err)
|
||||
}
|
||||
|
||||
filename := "verity-test-file"
|
||||
fd, _, err := newFileFD(ctx, vfsObj, root, filename, 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("newFileFD: %v", err)
|
||||
}
|
||||
filename := "verity-test-file"
|
||||
fd, _, 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)
|
||||
}
|
||||
// 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)
|
||||
}
|
||||
|
||||
rootLowerVD := root.Dentry().Impl().(*dentry).lowerVD
|
||||
if tc.remove {
|
||||
if tc.changeFile {
|
||||
if err := vfsObj.UnlinkAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(filename),
|
||||
}); err != nil {
|
||||
t.Fatalf("UnlinkAt: %v", err)
|
||||
rootLowerVD := root.Dentry().Impl().(*dentry).lowerVD
|
||||
if tc.remove {
|
||||
if tc.changeFile {
|
||||
if err := vfsObj.UnlinkAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(filename),
|
||||
}); err != nil {
|
||||
t.Fatalf("UnlinkAt: %v", err)
|
||||
}
|
||||
}
|
||||
if tc.changeMerkleFile {
|
||||
if err := vfsObj.UnlinkAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(merklePrefix + filename),
|
||||
}); err != nil {
|
||||
t.Fatalf("UnlinkAt: %v", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newFilename := "renamed-test-file"
|
||||
if tc.changeFile {
|
||||
if err := vfsObj.RenameAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(filename),
|
||||
}, &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(newFilename),
|
||||
}, &vfs.RenameOptions{}); err != nil {
|
||||
t.Fatalf("RenameAt: %v", err)
|
||||
}
|
||||
}
|
||||
if tc.changeMerkleFile {
|
||||
if err := vfsObj.RenameAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(merklePrefix + filename),
|
||||
}, &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(merklePrefix + newFilename),
|
||||
}, &vfs.RenameOptions{}); err != nil {
|
||||
t.Fatalf("UnlinkAt: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
if tc.changeMerkleFile {
|
||||
if err := vfsObj.UnlinkAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(merklePrefix + filename),
|
||||
}); err != nil {
|
||||
t.Fatalf("UnlinkAt: %v", err)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newFilename := "renamed-test-file"
|
||||
if tc.changeFile {
|
||||
if err := vfsObj.RenameAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(filename),
|
||||
}, &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(newFilename),
|
||||
}, &vfs.RenameOptions{}); err != nil {
|
||||
t.Fatalf("RenameAt: %v", err)
|
||||
}
|
||||
}
|
||||
if tc.changeMerkleFile {
|
||||
if err := vfsObj.RenameAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(merklePrefix + filename),
|
||||
}, &vfs.PathOperation{
|
||||
Root: rootLowerVD,
|
||||
Start: rootLowerVD,
|
||||
Path: fspath.Parse(merklePrefix + newFilename),
|
||||
}, &vfs.RenameOptions{}); err != nil {
|
||||
t.Fatalf("UnlinkAt: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure reopening the verity enabled file fails.
|
||||
if _, err = vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: root,
|
||||
Start: root,
|
||||
Path: fspath.Parse(filename),
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
Mode: linux.ModeRegular,
|
||||
}); err != syserror.EIO {
|
||||
t.Errorf("got OpenAt error: %v, expected EIO", err)
|
||||
// Ensure reopening the verity enabled file fails.
|
||||
if _, err = vfsObj.OpenAt(ctx, auth.CredentialsFromContext(ctx), &vfs.PathOperation{
|
||||
Root: root,
|
||||
Start: root,
|
||||
Path: fspath.Parse(filename),
|
||||
}, &vfs.OpenOptions{
|
||||
Flags: linux.O_RDONLY,
|
||||
Mode: linux.ModeRegular,
|
||||
}); err != syserror.EIO {
|
||||
t.Errorf("got OpenAt error: %v, expected EIO", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue