diff --git a/src/glibc/lind_syscall/lind_syscall_num.h b/src/glibc/lind_syscall/lind_syscall_num.h index 6a24cd669..6508a9c2a 100644 --- a/src/glibc/lind_syscall/lind_syscall_num.h +++ b/src/glibc/lind_syscall/lind_syscall_num.h @@ -109,6 +109,8 @@ #define STATFS_SYSCALL 137 #define FSTATFS_SYSCALL 138 #define GETHOSTNAME_SYSCALL 170 +#define SETXATTR_SYSCALL 188 +#define LISTXATTR_SYSCALL 194 #define FUTEX_SYSCALL 202 #define EPOLL_CREATE_SYSCALL 213 #define CLOCK_GETTIME_SYSCALL 228 diff --git a/src/glibc/sysdeps/unix/sysv/linux/i386/i686/listxattr.c b/src/glibc/sysdeps/unix/sysv/linux/i386/i686/listxattr.c new file mode 100644 index 000000000..762fa795d --- /dev/null +++ b/src/glibc/sysdeps/unix/sysv/linux/i386/i686/listxattr.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include + +/* List extended attributes associated with the file specified by path. + If list is NULL and size is zero, returns the buffer size needed. + Returns the size of the attribute list, or -1 and sets errno on error. */ +ssize_t +__listxattr (const char *path, char *list, size_t size) +{ + return MAKE_LEGACY_SYSCALL (LISTXATTR_SYSCALL, "syscall|listxattr", + (uint64_t) TRANSLATE_GUEST_POINTER_TO_HOST (path), + (uint64_t) TRANSLATE_GUEST_POINTER_TO_HOST (list), + (uint64_t) size, + NOTUSED, + NOTUSED, + NOTUSED, TRANSLATE_ERRNO_ON); +} +weak_alias(__listxattr, listxattr) diff --git a/src/glibc/sysdeps/unix/sysv/linux/i386/i686/setxattr.c b/src/glibc/sysdeps/unix/sysv/linux/i386/i686/setxattr.c new file mode 100644 index 000000000..0a96deb73 --- /dev/null +++ b/src/glibc/sysdeps/unix/sysv/linux/i386/i686/setxattr.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include +#include + +/* Set extended attributes on a file specified by path. + Returns 0 on success, or -1 and sets errno on error. */ +int +__setxattr (const char *path, const char *name, const void *value, + size_t size, int flags) +{ + return MAKE_LEGACY_SYSCALL (SETXATTR_SYSCALL, "syscall|setxattr", + (uint64_t) TRANSLATE_GUEST_POINTER_TO_HOST (path), + (uint64_t) TRANSLATE_GUEST_POINTER_TO_HOST (name), + (uint64_t) TRANSLATE_GUEST_POINTER_TO_HOST (value), + (uint64_t) size, + (uint64_t) flags, + NOTUSED, TRANSLATE_ERRNO_ON); +} +weak_alias(__setxattr, setxattr) diff --git a/src/rawposix/src/fs_calls.rs b/src/rawposix/src/fs_calls.rs index c988ab1a7..367b5bc61 100644 --- a/src/rawposix/src/fs_calls.rs +++ b/src/rawposix/src/fs_calls.rs @@ -4803,3 +4803,147 @@ pub extern "C" fn symlinkat_syscall( ret } + +/// Linux reference: https://man7.org/linux/man-pages/man2/setxattr.2.html +/// +/// Sets the value of an extended attribute identified by `name` +/// and associated with the given `path` in the filesystem. +/// +/// ## Arguments: +/// * `cageid` - Cage identifier +/// * `path_arg` - Path to the file +/// * `path_cageid` - Cage ID for path +/// * `name_arg` - Name of the extended attribute +/// * `name_cageid` - Cage ID for name +/// * `value_arg` - Pointer to the value to set +/// * `value_cageid` - Cage ID for value +/// * `size_arg` - Size of the value +/// * `size_cageid` - Cage ID for size +/// * `flags_arg` - Flags for setxattr (e.g., XATTR_CREATE, XATTR_REPLACE) +/// * `flags_cageid` - Cage ID for flags +/// +/// ## Returns: +/// On success, 0 is returned. On error, -1 is returned and errno is set appropriately. +pub extern "C" fn setxattr_syscall( + cageid: u64, + path_arg: u64, + path_cageid: u64, + name_arg: u64, + name_cageid: u64, + value_arg: u64, + value_cageid: u64, + size_arg: u64, + size_cageid: u64, + flags_arg: u64, + flags_cageid: u64, + arg6: u64, + arg6_cageid: u64, +) -> i32 { + // Type conversion for path + let path = match sc_convert_path_to_host(path_arg, path_cageid, cageid) { + Ok(path) => path, + Err(e) => return syscall_error(e, "setxattr", "path conversion failed"), + }; + + // Type conversion for name (attribute name, not a path - no path normalization needed) + let name_str = match get_cstr(name_arg) { + Ok(s) => s, + Err(_) => return syscall_error(Errno::EFAULT, "setxattr", "name conversion failed"), + }; + let name = match std::ffi::CString::new(name_str) { + Ok(s) => s, + Err(_) => return syscall_error(Errno::EINVAL, "setxattr", "name contains null byte"), + }; + + // Type conversion for value buffer + let value = sc_convert_buf(value_arg, value_cageid, cageid) as *const libc::c_void; + let size = sc_convert_sysarg_to_usize(size_arg, size_cageid, cageid); + let flags = sc_convert_sysarg_to_i32(flags_arg, flags_cageid, cageid); + + // Validate unused arg + if !sc_unusedarg(arg6, arg6_cageid) { + panic!( + "{}: unused arguments contain unexpected values -- security violation", + "setxattr_syscall" + ); + } + + // Call to kernel setxattr + let ret = unsafe { libc::setxattr(path.as_ptr(), name.as_ptr(), value, size, flags) }; + + if ret < 0 { + let errno = get_errno(); + return handle_errno(errno, "setxattr"); + } + + ret +} + +/// Linux reference: https://man7.org/linux/man-pages/man2/listxattr.2.html +/// +/// Retrieves the list of extended attribute names associated with the given `path`. +/// +/// ## Arguments: +/// * `cageid` - Cage identifier +/// * `path_arg` - Path to the file +/// * `path_cageid` - Cage ID for path +/// * `list_arg` - Pointer to buffer to store the list of attribute names +/// * `list_cageid` - Cage ID for list +/// * `size_arg` - Size of the buffer +/// * `size_cageid` - Cage ID for size +/// +/// ## Returns: +/// On success, returns the size of the list of attribute names. If `list` is NULL and `size` is zero, +/// returns the size of the buffer needed to store the list. +/// On error, -1 is returned and errno is set appropriately. +pub extern "C" fn listxattr_syscall( + cageid: u64, + path_arg: u64, + path_cageid: u64, + list_arg: u64, + list_cageid: u64, + size_arg: u64, + size_cageid: u64, + arg4: u64, + arg4_cageid: u64, + arg5: u64, + arg5_cageid: u64, + arg6: u64, + arg6_cageid: u64, +) -> i32 { + // Type conversion for path + let path = match sc_convert_path_to_host(path_arg, path_cageid, cageid) { + Ok(path) => path, + Err(e) => return syscall_error(e, "listxattr", "path conversion failed"), + }; + + // Type conversion for list buffer (may be NULL) + let list = if list_arg == 0 { + std::ptr::null_mut() + } else { + sc_convert_to_u8_mut(list_arg, list_cageid, cageid) as *mut libc::c_char + }; + let size = sc_convert_sysarg_to_usize(size_arg, size_cageid, cageid); + + // Validate unused args + if !(sc_unusedarg(arg4, arg4_cageid) + && sc_unusedarg(arg5, arg5_cageid) + && sc_unusedarg(arg6, arg6_cageid)) + { + panic!( + "{}: unused arguments contain unexpected values -- security violation", + "listxattr_syscall" + ); + } + + // Call to kernel listxattr + let ret = unsafe { libc::listxattr(path.as_ptr(), list, size) }; + + if ret < 0 { + let errno = get_errno(); + return handle_errno(errno, "listxattr"); + } + + // Convert ssize_t to i32 safely + ret.try_into().unwrap_or(i32::MAX) +} diff --git a/src/rawposix/src/syscall_table.rs b/src/rawposix/src/syscall_table.rs index 2ee30e3ac..68485de02 100644 --- a/src/rawposix/src/syscall_table.rs +++ b/src/rawposix/src/syscall_table.rs @@ -8,13 +8,14 @@ use super::fs_calls::{ close_syscall, dup2_syscall, dup3_syscall, dup_syscall, fchdir_syscall, fchmod_syscall, fcntl_syscall, fdatasync_syscall, flock_syscall, fstat_syscall, fstatfs_syscall, fsync_syscall, ftruncate_syscall, futex_syscall, getcwd_syscall, getdents_syscall, getrandom_syscall, - ioctl_syscall, link_syscall, lseek_syscall, lstat_syscall, mkdir_syscall, mknod_syscall, - mmap_syscall, mprotect_syscall, munmap_syscall, nanosleep_time64_syscall, open_syscall, - openat_syscall, pipe2_syscall, pipe_syscall, pread_syscall, preadv_syscall, pwrite_syscall, - pwritev_syscall, read_syscall, readlink_syscall, readlinkat_syscall, readv_syscall, - rename_syscall, rmdir_syscall, shmat_syscall, shmctl_syscall, shmdt_syscall, shmget_syscall, - stat_syscall, statfs_syscall, symlink_syscall, symlinkat_syscall, sync_file_range_syscall, - truncate_syscall, unlink_syscall, unlinkat_syscall, write_syscall, writev_syscall, + ioctl_syscall, link_syscall, listxattr_syscall, lseek_syscall, lstat_syscall, mkdir_syscall, + mknod_syscall, mmap_syscall, mprotect_syscall, munmap_syscall, nanosleep_time64_syscall, + open_syscall, openat_syscall, pipe2_syscall, pipe_syscall, pread_syscall, preadv_syscall, + pwrite_syscall, pwritev_syscall, read_syscall, readlink_syscall, readlinkat_syscall, + readv_syscall, rename_syscall, rmdir_syscall, setxattr_syscall, shmat_syscall, shmctl_syscall, + shmdt_syscall, shmget_syscall, stat_syscall, statfs_syscall, symlink_syscall, + symlinkat_syscall, sync_file_range_syscall, truncate_syscall, unlink_syscall, unlinkat_syscall, + write_syscall, writev_syscall, }; use super::init::RawCallFunc; use super::net_calls::{ @@ -133,6 +134,8 @@ pub const SYSCALL_TABLE: &[(u64, RawCallFunc)] = &[ syscall_const::GETHOSTNAME_SYSCALL as u64, gethostname_syscall, ), + (188 as u64, setxattr_syscall), + (194 as u64, listxattr_syscall), (syscall_const::FUTEX_SYSCALL as u64, futex_syscall), ( syscall_const::EPOLL_CREATE_SYSCALL as u64,