github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/syscalls/linux/vfs2/xattr.go (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package vfs2
    16  
    17  import (
    18  	"bytes"
    19  
    20  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    21  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    22  	"github.com/SagerNet/gvisor/pkg/gohacks"
    23  	"github.com/SagerNet/gvisor/pkg/sentry/arch"
    24  	"github.com/SagerNet/gvisor/pkg/sentry/kernel"
    25  	"github.com/SagerNet/gvisor/pkg/sentry/vfs"
    26  	"github.com/SagerNet/gvisor/pkg/syserror"
    27  
    28  	"github.com/SagerNet/gvisor/pkg/hostarch"
    29  )
    30  
    31  // ListXattr implements Linux syscall listxattr(2).
    32  func ListXattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    33  	return listxattr(t, args, followFinalSymlink)
    34  }
    35  
    36  // Llistxattr implements Linux syscall llistxattr(2).
    37  func Llistxattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    38  	return listxattr(t, args, nofollowFinalSymlink)
    39  }
    40  
    41  func listxattr(t *kernel.Task, args arch.SyscallArguments, shouldFollowFinalSymlink shouldFollowFinalSymlink) (uintptr, *kernel.SyscallControl, error) {
    42  	pathAddr := args[0].Pointer()
    43  	listAddr := args[1].Pointer()
    44  	size := args[2].SizeT()
    45  
    46  	path, err := copyInPath(t, pathAddr)
    47  	if err != nil {
    48  		return 0, nil, err
    49  	}
    50  	tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink)
    51  	if err != nil {
    52  		return 0, nil, err
    53  	}
    54  	defer tpop.Release(t)
    55  
    56  	names, err := t.Kernel().VFS().ListXattrAt(t, t.Credentials(), &tpop.pop, uint64(size))
    57  	if err != nil {
    58  		return 0, nil, err
    59  	}
    60  	n, err := copyOutXattrNameList(t, listAddr, size, names)
    61  	if err != nil {
    62  		return 0, nil, err
    63  	}
    64  	return uintptr(n), nil, nil
    65  }
    66  
    67  // Flistxattr implements Linux syscall flistxattr(2).
    68  func Flistxattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    69  	fd := args[0].Int()
    70  	listAddr := args[1].Pointer()
    71  	size := args[2].SizeT()
    72  
    73  	file := t.GetFileVFS2(fd)
    74  	if file == nil {
    75  		return 0, nil, linuxerr.EBADF
    76  	}
    77  	defer file.DecRef(t)
    78  
    79  	names, err := file.ListXattr(t, uint64(size))
    80  	if err != nil {
    81  		return 0, nil, err
    82  	}
    83  	n, err := copyOutXattrNameList(t, listAddr, size, names)
    84  	if err != nil {
    85  		return 0, nil, err
    86  	}
    87  	return uintptr(n), nil, nil
    88  }
    89  
    90  // GetXattr implements Linux syscall getxattr(2).
    91  func GetXattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    92  	return getxattr(t, args, followFinalSymlink)
    93  }
    94  
    95  // Lgetxattr implements Linux syscall lgetxattr(2).
    96  func Lgetxattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
    97  	return getxattr(t, args, nofollowFinalSymlink)
    98  }
    99  
   100  func getxattr(t *kernel.Task, args arch.SyscallArguments, shouldFollowFinalSymlink shouldFollowFinalSymlink) (uintptr, *kernel.SyscallControl, error) {
   101  	pathAddr := args[0].Pointer()
   102  	nameAddr := args[1].Pointer()
   103  	valueAddr := args[2].Pointer()
   104  	size := args[3].SizeT()
   105  
   106  	path, err := copyInPath(t, pathAddr)
   107  	if err != nil {
   108  		return 0, nil, err
   109  	}
   110  	tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink)
   111  	if err != nil {
   112  		return 0, nil, err
   113  	}
   114  	defer tpop.Release(t)
   115  
   116  	name, err := copyInXattrName(t, nameAddr)
   117  	if err != nil {
   118  		return 0, nil, err
   119  	}
   120  
   121  	value, err := t.Kernel().VFS().GetXattrAt(t, t.Credentials(), &tpop.pop, &vfs.GetXattrOptions{
   122  		Name: name,
   123  		Size: uint64(size),
   124  	})
   125  	if err != nil {
   126  		return 0, nil, err
   127  	}
   128  	n, err := copyOutXattrValue(t, valueAddr, size, value)
   129  	if err != nil {
   130  		return 0, nil, err
   131  	}
   132  	return uintptr(n), nil, nil
   133  }
   134  
   135  // Fgetxattr implements Linux syscall fgetxattr(2).
   136  func Fgetxattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   137  	fd := args[0].Int()
   138  	nameAddr := args[1].Pointer()
   139  	valueAddr := args[2].Pointer()
   140  	size := args[3].SizeT()
   141  
   142  	file := t.GetFileVFS2(fd)
   143  	if file == nil {
   144  		return 0, nil, linuxerr.EBADF
   145  	}
   146  	defer file.DecRef(t)
   147  
   148  	name, err := copyInXattrName(t, nameAddr)
   149  	if err != nil {
   150  		return 0, nil, err
   151  	}
   152  
   153  	value, err := file.GetXattr(t, &vfs.GetXattrOptions{Name: name, Size: uint64(size)})
   154  	if err != nil {
   155  		return 0, nil, err
   156  	}
   157  	n, err := copyOutXattrValue(t, valueAddr, size, value)
   158  	if err != nil {
   159  		return 0, nil, err
   160  	}
   161  	return uintptr(n), nil, nil
   162  }
   163  
   164  // SetXattr implements Linux syscall setxattr(2).
   165  func SetXattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   166  	return 0, nil, setxattr(t, args, followFinalSymlink)
   167  }
   168  
   169  // Lsetxattr implements Linux syscall lsetxattr(2).
   170  func Lsetxattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   171  	return 0, nil, setxattr(t, args, nofollowFinalSymlink)
   172  }
   173  
   174  func setxattr(t *kernel.Task, args arch.SyscallArguments, shouldFollowFinalSymlink shouldFollowFinalSymlink) error {
   175  	pathAddr := args[0].Pointer()
   176  	nameAddr := args[1].Pointer()
   177  	valueAddr := args[2].Pointer()
   178  	size := args[3].SizeT()
   179  	flags := args[4].Int()
   180  
   181  	if flags&^(linux.XATTR_CREATE|linux.XATTR_REPLACE) != 0 {
   182  		return linuxerr.EINVAL
   183  	}
   184  
   185  	path, err := copyInPath(t, pathAddr)
   186  	if err != nil {
   187  		return err
   188  	}
   189  	tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink)
   190  	if err != nil {
   191  		return err
   192  	}
   193  	defer tpop.Release(t)
   194  
   195  	name, err := copyInXattrName(t, nameAddr)
   196  	if err != nil {
   197  		return err
   198  	}
   199  	value, err := copyInXattrValue(t, valueAddr, size)
   200  	if err != nil {
   201  		return err
   202  	}
   203  
   204  	return t.Kernel().VFS().SetXattrAt(t, t.Credentials(), &tpop.pop, &vfs.SetXattrOptions{
   205  		Name:  name,
   206  		Value: value,
   207  		Flags: uint32(flags),
   208  	})
   209  }
   210  
   211  // Fsetxattr implements Linux syscall fsetxattr(2).
   212  func Fsetxattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   213  	fd := args[0].Int()
   214  	nameAddr := args[1].Pointer()
   215  	valueAddr := args[2].Pointer()
   216  	size := args[3].SizeT()
   217  	flags := args[4].Int()
   218  
   219  	if flags&^(linux.XATTR_CREATE|linux.XATTR_REPLACE) != 0 {
   220  		return 0, nil, linuxerr.EINVAL
   221  	}
   222  
   223  	file := t.GetFileVFS2(fd)
   224  	if file == nil {
   225  		return 0, nil, linuxerr.EBADF
   226  	}
   227  	defer file.DecRef(t)
   228  
   229  	name, err := copyInXattrName(t, nameAddr)
   230  	if err != nil {
   231  		return 0, nil, err
   232  	}
   233  	value, err := copyInXattrValue(t, valueAddr, size)
   234  	if err != nil {
   235  		return 0, nil, err
   236  	}
   237  
   238  	return 0, nil, file.SetXattr(t, &vfs.SetXattrOptions{
   239  		Name:  name,
   240  		Value: value,
   241  		Flags: uint32(flags),
   242  	})
   243  }
   244  
   245  // RemoveXattr implements Linux syscall removexattr(2).
   246  func RemoveXattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   247  	return 0, nil, removexattr(t, args, followFinalSymlink)
   248  }
   249  
   250  // Lremovexattr implements Linux syscall lremovexattr(2).
   251  func Lremovexattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   252  	return 0, nil, removexattr(t, args, nofollowFinalSymlink)
   253  }
   254  
   255  func removexattr(t *kernel.Task, args arch.SyscallArguments, shouldFollowFinalSymlink shouldFollowFinalSymlink) error {
   256  	pathAddr := args[0].Pointer()
   257  	nameAddr := args[1].Pointer()
   258  
   259  	path, err := copyInPath(t, pathAddr)
   260  	if err != nil {
   261  		return err
   262  	}
   263  	tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink)
   264  	if err != nil {
   265  		return err
   266  	}
   267  	defer tpop.Release(t)
   268  
   269  	name, err := copyInXattrName(t, nameAddr)
   270  	if err != nil {
   271  		return err
   272  	}
   273  
   274  	return t.Kernel().VFS().RemoveXattrAt(t, t.Credentials(), &tpop.pop, name)
   275  }
   276  
   277  // Fremovexattr implements Linux syscall fremovexattr(2).
   278  func Fremovexattr(t *kernel.Task, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   279  	fd := args[0].Int()
   280  	nameAddr := args[1].Pointer()
   281  
   282  	file := t.GetFileVFS2(fd)
   283  	if file == nil {
   284  		return 0, nil, linuxerr.EBADF
   285  	}
   286  	defer file.DecRef(t)
   287  
   288  	name, err := copyInXattrName(t, nameAddr)
   289  	if err != nil {
   290  		return 0, nil, err
   291  	}
   292  
   293  	return 0, nil, file.RemoveXattr(t, name)
   294  }
   295  
   296  func copyInXattrName(t *kernel.Task, nameAddr hostarch.Addr) (string, error) {
   297  	name, err := t.CopyInString(nameAddr, linux.XATTR_NAME_MAX+1)
   298  	if err != nil {
   299  		if linuxerr.Equals(linuxerr.ENAMETOOLONG, err) {
   300  			return "", syserror.ERANGE
   301  		}
   302  		return "", err
   303  	}
   304  	if len(name) == 0 {
   305  		return "", syserror.ERANGE
   306  	}
   307  	return name, nil
   308  }
   309  
   310  func copyOutXattrNameList(t *kernel.Task, listAddr hostarch.Addr, size uint, names []string) (int, error) {
   311  	if size > linux.XATTR_LIST_MAX {
   312  		size = linux.XATTR_LIST_MAX
   313  	}
   314  	var buf bytes.Buffer
   315  	for _, name := range names {
   316  		buf.WriteString(name)
   317  		buf.WriteByte(0)
   318  	}
   319  	if size == 0 {
   320  		// Return the size that would be required to accomodate the list.
   321  		return buf.Len(), nil
   322  	}
   323  	if buf.Len() > int(size) {
   324  		if size >= linux.XATTR_LIST_MAX {
   325  			return 0, linuxerr.E2BIG
   326  		}
   327  		return 0, syserror.ERANGE
   328  	}
   329  	return t.CopyOutBytes(listAddr, buf.Bytes())
   330  }
   331  
   332  func copyInXattrValue(t *kernel.Task, valueAddr hostarch.Addr, size uint) (string, error) {
   333  	if size > linux.XATTR_SIZE_MAX {
   334  		return "", linuxerr.E2BIG
   335  	}
   336  	buf := make([]byte, size)
   337  	if _, err := t.CopyInBytes(valueAddr, buf); err != nil {
   338  		return "", err
   339  	}
   340  	return gohacks.StringFromImmutableBytes(buf), nil
   341  }
   342  
   343  func copyOutXattrValue(t *kernel.Task, valueAddr hostarch.Addr, size uint, value string) (int, error) {
   344  	if size > linux.XATTR_SIZE_MAX {
   345  		size = linux.XATTR_SIZE_MAX
   346  	}
   347  	if size == 0 {
   348  		// Return the size that would be required to accomodate the value.
   349  		return len(value), nil
   350  	}
   351  	if len(value) > int(size) {
   352  		if size >= linux.XATTR_SIZE_MAX {
   353  			return 0, linuxerr.E2BIG
   354  		}
   355  		return 0, syserror.ERANGE
   356  	}
   357  	return t.CopyOutBytes(valueAddr, gohacks.ImmutableBytesFromString(value))
   358  }