Make gVisor hard link check match Linux's.
Linux permits hard-linking if the target is owned by the user OR the target has Read+Write permission. PiperOrigin-RevId: 213024613 Change-Id: If642066317b568b99084edd33ee4e8822ec9cbb3
This commit is contained in:
parent
0380bcb3a4
commit
b84bfa570d
|
@ -773,6 +773,11 @@ func (d *Dirent) CreateHardLink(ctx context.Context, root *Dirent, target *Diren
|
|||
return syscall.EXDEV
|
||||
}
|
||||
|
||||
// Directories are never linkable. See fs/namei.c:vfs_link.
|
||||
if IsDir(target.Inode.StableAttr) {
|
||||
return syscall.EPERM
|
||||
}
|
||||
|
||||
return d.genericCreate(ctx, root, name, func() error {
|
||||
if err := d.Inode.CreateHardLink(ctx, d, target, name); err != nil {
|
||||
return err
|
||||
|
|
|
@ -1122,15 +1122,32 @@ func Symlinkat(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.Sys
|
|||
//
|
||||
// This corresponds to Linux's fs/namei.c:may_linkat.
|
||||
func mayLinkAt(t *kernel.Task, target *fs.Inode) error {
|
||||
// Linux will impose the following restrictions on hard links only if
|
||||
// sysctl_protected_hardlinks is enabled. The kernel disables this
|
||||
// setting by default for backward compatibility (see commit
|
||||
// 561ec64ae67e), but also recommends that distributions enable it (and
|
||||
// Debian does:
|
||||
// https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=889098).
|
||||
//
|
||||
// gVisor currently behaves as though sysctl_protected_hardlinks is
|
||||
// always enabled, and thus imposes the following restrictions on hard
|
||||
// links.
|
||||
|
||||
// Technically Linux is more restrictive in 3.11.10 (requires CAP_FOWNER in
|
||||
// root user namespace); this is from the later f2ca379642d7 "namei: permit
|
||||
// linking with CAP_FOWNER in userns".
|
||||
if !target.CheckOwnership(t) {
|
||||
return syserror.EPERM
|
||||
if target.CheckOwnership(t) {
|
||||
// fs/namei.c:may_linkat: "Source inode owner (or CAP_FOWNER)
|
||||
// can hardlink all they like."
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check that the target is not a directory and that permissions are okay.
|
||||
if fs.IsDir(target.StableAttr) || target.CheckPermission(t, fs.PermMask{Read: true, Write: true}) != nil {
|
||||
// If we are not the owner, then the file must be regular and have
|
||||
// Read+Write permissions.
|
||||
if !fs.IsRegular(target.StableAttr) {
|
||||
return syserror.EPERM
|
||||
}
|
||||
if target.CheckPermission(t, fs.PermMask{Read: true, Write: true}) != nil {
|
||||
return syserror.EPERM
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue