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