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:
Nicolas Lacasse 2018-09-14 12:28:43 -07:00 committed by Shentubot
parent 0380bcb3a4
commit b84bfa570d
2 changed files with 26 additions and 4 deletions

View File

@ -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

View File

@ -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
}