github.com/MerlinKodo/gvisor@v0.0.0-20231110090155-957f62ecf90e/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/MerlinKodo/gvisor/pkg/abi/linux"
    21  	"github.com/MerlinKodo/gvisor/pkg/errors/linuxerr"
    22  	"github.com/MerlinKodo/gvisor/pkg/gohacks"
    23  	"github.com/MerlinKodo/gvisor/pkg/hostarch"
    24  	"github.com/MerlinKodo/gvisor/pkg/sentry/arch"
    25  	"github.com/MerlinKodo/gvisor/pkg/sentry/kernel"
    26  	"github.com/MerlinKodo/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  	path, err := copyInPath(t, pathAddr)
   105  	if err != nil {
   106  		return 0, nil, err
   107  	}
   108  	tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink)
   109  	if err != nil {
   110  		return 0, nil, err
   111  	}
   112  	defer tpop.Release(t)
   113  
   114  	name, err := copyInXattrName(t, nameAddr)
   115  	if err != nil {
   116  		return 0, nil, err
   117  	}
   118  
   119  	value, err := t.Kernel().VFS().GetXattrAt(t, t.Credentials(), &tpop.pop, &vfs.GetXattrOptions{
   120  		Name: name,
   121  		Size: uint64(size),
   122  	})
   123  	if err != nil {
   124  		return 0, nil, err
   125  	}
   126  	n, err := copyOutXattrValue(t, valueAddr, size, value)
   127  	if err != nil {
   128  		return 0, nil, err
   129  	}
   130  	return uintptr(n), nil, nil
   131  }
   132  
   133  // Fgetxattr implements Linux syscall fgetxattr(2).
   134  func Fgetxattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   135  	fd := args[0].Int()
   136  	nameAddr := args[1].Pointer()
   137  	valueAddr := args[2].Pointer()
   138  	size := args[3].SizeT()
   139  
   140  	file := t.GetFile(fd)
   141  	if file == nil {
   142  		return 0, nil, linuxerr.EBADF
   143  	}
   144  	defer file.DecRef(t)
   145  
   146  	name, err := copyInXattrName(t, nameAddr)
   147  	if err != nil {
   148  		return 0, nil, err
   149  	}
   150  
   151  	value, err := file.GetXattr(t, &vfs.GetXattrOptions{Name: name, Size: uint64(size)})
   152  	if err != nil {
   153  		return 0, nil, err
   154  	}
   155  	n, err := copyOutXattrValue(t, valueAddr, size, value)
   156  	if err != nil {
   157  		return 0, nil, err
   158  	}
   159  	return uintptr(n), nil, nil
   160  }
   161  
   162  // SetXattr implements Linux syscall setxattr(2).
   163  func SetXattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   164  	return 0, nil, setxattr(t, args, followFinalSymlink)
   165  }
   166  
   167  // Lsetxattr implements Linux syscall lsetxattr(2).
   168  func Lsetxattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   169  	return 0, nil, setxattr(t, args, nofollowFinalSymlink)
   170  }
   171  
   172  func setxattr(t *kernel.Task, args arch.SyscallArguments, shouldFollowFinalSymlink shouldFollowFinalSymlink) error {
   173  	pathAddr := args[0].Pointer()
   174  	nameAddr := args[1].Pointer()
   175  	valueAddr := args[2].Pointer()
   176  	size := args[3].SizeT()
   177  	flags := args[4].Int()
   178  
   179  	if flags&^(linux.XATTR_CREATE|linux.XATTR_REPLACE) != 0 {
   180  		return linuxerr.EINVAL
   181  	}
   182  
   183  	path, err := copyInPath(t, pathAddr)
   184  	if err != nil {
   185  		return err
   186  	}
   187  	tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink)
   188  	if err != nil {
   189  		return err
   190  	}
   191  	defer tpop.Release(t)
   192  
   193  	name, err := copyInXattrName(t, nameAddr)
   194  	if err != nil {
   195  		return err
   196  	}
   197  	value, err := copyInXattrValue(t, valueAddr, size)
   198  	if err != nil {
   199  		return err
   200  	}
   201  
   202  	return t.Kernel().VFS().SetXattrAt(t, t.Credentials(), &tpop.pop, &vfs.SetXattrOptions{
   203  		Name:  name,
   204  		Value: value,
   205  		Flags: uint32(flags),
   206  	})
   207  }
   208  
   209  // Fsetxattr implements Linux syscall fsetxattr(2).
   210  func Fsetxattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   211  	fd := args[0].Int()
   212  	nameAddr := args[1].Pointer()
   213  	valueAddr := args[2].Pointer()
   214  	size := args[3].SizeT()
   215  	flags := args[4].Int()
   216  
   217  	if flags&^(linux.XATTR_CREATE|linux.XATTR_REPLACE) != 0 {
   218  		return 0, nil, linuxerr.EINVAL
   219  	}
   220  
   221  	file := t.GetFile(fd)
   222  	if file == nil {
   223  		return 0, nil, linuxerr.EBADF
   224  	}
   225  	defer file.DecRef(t)
   226  
   227  	name, err := copyInXattrName(t, nameAddr)
   228  	if err != nil {
   229  		return 0, nil, err
   230  	}
   231  	value, err := copyInXattrValue(t, valueAddr, size)
   232  	if err != nil {
   233  		return 0, nil, err
   234  	}
   235  
   236  	return 0, nil, file.SetXattr(t, &vfs.SetXattrOptions{
   237  		Name:  name,
   238  		Value: value,
   239  		Flags: uint32(flags),
   240  	})
   241  }
   242  
   243  // RemoveXattr implements Linux syscall removexattr(2).
   244  func RemoveXattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   245  	return 0, nil, removexattr(t, args, followFinalSymlink)
   246  }
   247  
   248  // Lremovexattr implements Linux syscall lremovexattr(2).
   249  func Lremovexattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   250  	return 0, nil, removexattr(t, args, nofollowFinalSymlink)
   251  }
   252  
   253  func removexattr(t *kernel.Task, args arch.SyscallArguments, shouldFollowFinalSymlink shouldFollowFinalSymlink) error {
   254  	pathAddr := args[0].Pointer()
   255  	nameAddr := args[1].Pointer()
   256  
   257  	path, err := copyInPath(t, pathAddr)
   258  	if err != nil {
   259  		return err
   260  	}
   261  	tpop, err := getTaskPathOperation(t, linux.AT_FDCWD, path, disallowEmptyPath, shouldFollowFinalSymlink)
   262  	if err != nil {
   263  		return err
   264  	}
   265  	defer tpop.Release(t)
   266  
   267  	name, err := copyInXattrName(t, nameAddr)
   268  	if err != nil {
   269  		return err
   270  	}
   271  
   272  	return t.Kernel().VFS().RemoveXattrAt(t, t.Credentials(), &tpop.pop, name)
   273  }
   274  
   275  // Fremovexattr implements Linux syscall fremovexattr(2).
   276  func Fremovexattr(t *kernel.Task, sysno uintptr, args arch.SyscallArguments) (uintptr, *kernel.SyscallControl, error) {
   277  	fd := args[0].Int()
   278  	nameAddr := args[1].Pointer()
   279  
   280  	file := t.GetFile(fd)
   281  	if file == nil {
   282  		return 0, nil, linuxerr.EBADF
   283  	}
   284  	defer file.DecRef(t)
   285  
   286  	name, err := copyInXattrName(t, nameAddr)
   287  	if err != nil {
   288  		return 0, nil, err
   289  	}
   290  
   291  	return 0, nil, file.RemoveXattr(t, name)
   292  }
   293  
   294  func copyInXattrName(t *kernel.Task, nameAddr hostarch.Addr) (string, error) {
   295  	name, err := t.CopyInString(nameAddr, linux.XATTR_NAME_MAX+1)
   296  	if err != nil {
   297  		if linuxerr.Equals(linuxerr.ENAMETOOLONG, err) {
   298  			return "", linuxerr.ERANGE
   299  		}
   300  		return "", err
   301  	}
   302  	if len(name) == 0 {
   303  		return "", linuxerr.ERANGE
   304  	}
   305  	return name, nil
   306  }
   307  
   308  func copyOutXattrNameList(t *kernel.Task, listAddr hostarch.Addr, size uint, names []string) (int, error) {
   309  	if size > linux.XATTR_LIST_MAX {
   310  		size = linux.XATTR_LIST_MAX
   311  	}
   312  	var buf bytes.Buffer
   313  	for _, name := range names {
   314  		buf.WriteString(name)
   315  		buf.WriteByte(0)
   316  	}
   317  	if size == 0 {
   318  		// Return the size that would be required to accommodate the list.
   319  		return buf.Len(), nil
   320  	}
   321  	if buf.Len() > int(size) {
   322  		if size >= linux.XATTR_LIST_MAX {
   323  			return 0, linuxerr.E2BIG
   324  		}
   325  		return 0, linuxerr.ERANGE
   326  	}
   327  	return t.CopyOutBytes(listAddr, buf.Bytes())
   328  }
   329  
   330  func copyInXattrValue(t *kernel.Task, valueAddr hostarch.Addr, size uint) (string, error) {
   331  	if size > linux.XATTR_SIZE_MAX {
   332  		return "", linuxerr.E2BIG
   333  	}
   334  	buf := make([]byte, size)
   335  	if _, err := t.CopyInBytes(valueAddr, buf); err != nil {
   336  		return "", err
   337  	}
   338  	return gohacks.StringFromImmutableBytes(buf), nil
   339  }
   340  
   341  func copyOutXattrValue(t *kernel.Task, valueAddr hostarch.Addr, size uint, value string) (int, error) {
   342  	if size > linux.XATTR_SIZE_MAX {
   343  		size = linux.XATTR_SIZE_MAX
   344  	}
   345  	if size == 0 {
   346  		// Return the size that would be required to accommodate the value.
   347  		return len(value), nil
   348  	}
   349  	if len(value) > int(size) {
   350  		if size >= linux.XATTR_SIZE_MAX {
   351  			return 0, linuxerr.E2BIG
   352  		}
   353  		return 0, linuxerr.ERANGE
   354  	}
   355  	return t.CopyOutBytes(valueAddr, gohacks.ImmutableBytesFromString(value))
   356  }