Add extended attribute (xattr) syscalls: setxattr, getxattr, listxattr and removexattr

This commit is contained in:
Shaowei Song 2025-03-28 05:58:37 +00:00 committed by Tate, Hongliang Tian
parent 8b5a6f0d58
commit a47eda413c
11 changed files with 649 additions and 15 deletions

View File

@ -15,7 +15,7 @@ support the loading of Linux kernel modules.
## System Calls
At the time of writing,
Asterinas implements 190 out of the 336 system calls
Asterinas implements 204 out of the 336 system calls
provided by Linux on x86-64 architecture.
| Numbers | Names | Is Implemented |
@ -208,18 +208,18 @@ provided by Linux on x86-64 architecture.
| 185 | security | ❌ |
| 186 | gettid | ✅ |
| 187 | readahead | ❌ |
| 188 | setxattr | |
| 189 | lsetxattr | |
| 190 | fsetxattr | |
| 191 | getxattr | |
| 192 | lgetxattr | |
| 193 | fgetxattr | |
| 194 | listxattr | |
| 195 | llistxattr | |
| 196 | flistxattr | |
| 197 | removexattr | |
| 198 | lremovexattr | |
| 199 | fremovexattr | |
| 188 | setxattr | |
| 189 | lsetxattr | |
| 190 | fsetxattr | |
| 191 | getxattr | |
| 192 | lgetxattr | |
| 193 | fgetxattr | |
| 194 | listxattr | |
| 195 | llistxattr | |
| 196 | flistxattr | |
| 197 | removexattr | |
| 198 | lremovexattr | |
| 199 | fremovexattr | |
| 200 | tkill | ❌ |
| 201 | time | ✅ |
| 202 | futex | ✅ |

View File

@ -17,7 +17,8 @@ use crate::{
fs::{
path::mount::MountNode,
utils::{
FileSystem, Inode, InodeMode, InodeType, Metadata, MknodType, Permission, NAME_MAX,
FileSystem, Inode, InodeMode, InodeType, Metadata, MknodType, Permission, XattrName,
XattrNamespace, XattrSetFlags, NAME_MAX,
},
},
prelude::*,
@ -356,6 +357,19 @@ impl Dentry_ {
pub fn ctime(&self) -> Duration;
pub fn set_ctime(&self, time: Duration);
pub fn is_dentry_cacheable(&self) -> bool;
pub fn set_xattr(
&self,
name: XattrName,
value_reader: &mut VmReader,
flags: XattrSetFlags,
) -> Result<()>;
pub fn get_xattr(&self, name: XattrName, value_writer: &mut VmWriter) -> Result<usize>;
pub fn list_xattr(
&self,
namespace: XattrNamespace,
list_writer: &mut VmWriter,
) -> Result<usize>;
pub fn remove_xattr(&self, name: XattrName) -> Result<()>;
}
impl Debug for Dentry_ {
@ -769,4 +783,17 @@ impl Dentry {
pub fn inode(&self) -> &Arc<dyn Inode>;
pub fn is_root_of_mount(&self) -> bool;
pub fn is_mountpoint(&self) -> bool;
pub fn set_xattr(
&self,
name: XattrName,
value_reader: &mut VmReader,
flags: XattrSetFlags,
) -> Result<()>;
pub fn get_xattr(&self, name: XattrName, value_writer: &mut VmWriter) -> Result<usize>;
pub fn list_xattr(
&self,
namespace: XattrNamespace,
list_writer: &mut VmWriter,
) -> Result<usize>;
pub fn remove_xattr(&self, name: XattrName) -> Result<()>;
}

View File

@ -8,7 +8,10 @@ use aster_rights::Full;
use core2::io::{Error as IoError, ErrorKind as IoErrorKind, Result as IoResult, Write};
use ostd::task::Task;
use super::{AccessMode, DirentVisitor, FallocMode, FileSystem, IoctlCmd};
use super::{
AccessMode, DirentVisitor, FallocMode, FileSystem, IoctlCmd, XattrName, XattrNamespace,
XattrSetFlags,
};
use crate::{
events::IoEvents,
fs::device::{Device, DeviceType},
@ -497,6 +500,27 @@ pub trait Inode: Any + Sync + Send {
None
}
fn set_xattr(
&self,
name: XattrName,
value_reader: &mut VmReader,
flags: XattrSetFlags,
) -> Result<()> {
Err(Error::new(Errno::EOPNOTSUPP))
}
fn get_xattr(&self, name: XattrName, value_writer: &mut VmWriter) -> Result<usize> {
Err(Error::new(Errno::EOPNOTSUPP))
}
fn list_xattr(&self, namespace: XattrNamespace, list_writer: &mut VmWriter) -> Result<usize> {
Err(Error::new(Errno::EOPNOTSUPP))
}
fn remove_xattr(&self, name: XattrName) -> Result<()> {
Err(Error::new(Errno::EOPNOTSUPP))
}
/// Used to check for read/write/execute permissions on a file.
///
/// Similar to Linux, using "fsuid" here allows setting filesystem permissions

View File

@ -19,6 +19,10 @@ pub use range_lock::{
FileRange, RangeLockItem, RangeLockItemBuilder, RangeLockList, RangeLockType, OFFSET_MAX,
};
pub use status_flags::StatusFlags;
pub use xattr::{
XattrName, XattrNamespace, XattrSetFlags, XATTR_LIST_MAX_LEN, XATTR_NAME_MAX_LEN,
XATTR_VALUE_MAX_LEN,
};
mod access_mode;
mod channel;
@ -35,6 +39,7 @@ mod page_cache;
mod random_test;
mod range_lock;
mod status_flags;
mod xattr;
use core::{
borrow::Borrow,

View File

@ -0,0 +1,93 @@
// SPDX-License-Identifier: MPL-2.0
use crate::prelude::*;
pub const XATTR_NAME_MAX_LEN: usize = 255;
pub const XATTR_VALUE_MAX_LEN: usize = 65536;
pub const XATTR_LIST_MAX_LEN: usize = 65536;
/// Represents different namespaces with different capabilities
/// for extended attributes (xattrs).
#[derive(Debug, PartialEq, Eq, Clone, Copy, TryFromInt, Hash)]
#[repr(u8)]
pub enum XattrNamespace {
User = 1,
Trusted = 2,
System = 3,
Security = 4,
// More namespaces can be added here.
}
/// Represents the name of an xattr. It includes both a valid namespace
/// and a full name string slice, which contains the namespace prefix.
///
/// For example, "user.foo" is a valid xattr name, and its namespace
/// is `XattrNamespace::User`.
#[derive(Debug, Hash)]
pub struct XattrName<'a> {
namespace: XattrNamespace,
full_name: &'a str,
}
impl XattrNamespace {
pub fn try_from_full_name(full_name: &str) -> Option<XattrNamespace> {
const USER_PREFIX: &str = "user.";
const TRUSTED_PREFIX: &str = "trusted.";
const SYSTEM_PREFIX: &str = "system.";
const SECURITY_PREFIX: &str = "security.";
if full_name.starts_with(USER_PREFIX) {
Some(XattrNamespace::User)
} else if full_name.starts_with(TRUSTED_PREFIX) {
Some(XattrNamespace::Trusted)
} else if full_name.starts_with(SYSTEM_PREFIX) {
Some(XattrNamespace::System)
} else if full_name.starts_with(SECURITY_PREFIX) {
Some(XattrNamespace::Security)
} else {
None
}
}
pub fn is_user(&self) -> bool {
matches!(self, XattrNamespace::User)
}
pub fn is_admin(&self) -> bool {
matches!(self, XattrNamespace::Trusted)
}
}
impl<'a> XattrName<'a> {
pub fn try_from_full_name(full_name: &'a str) -> Option<Self> {
let namespace = XattrNamespace::try_from_full_name(full_name)?;
Some(Self {
namespace,
full_name,
})
}
pub fn namespace(&self) -> XattrNamespace {
self.namespace
}
pub const fn full_name(&self) -> &'a str {
self.full_name
}
pub const fn full_name_len(&self) -> usize {
self.full_name.len()
}
}
bitflags::bitflags! {
/// Flags for setting an xattr value.
pub struct XattrSetFlags: u8 {
/// Creates a new xattr if it doesn't exist, or replaces the value if it does.
const CREATE_OR_REPLACE = 0;
/// Creates a new xattr, fails if it already exists.
const CREATE_ONLY = 1;
/// Replaces the value of an existing xattr, fails if it doesn't exist.
const REPLACE_ONLY = 2;
}
}

View File

@ -52,11 +52,13 @@ use crate::syscall::{
gettid::sys_gettid,
gettimeofday::sys_gettimeofday,
getuid::sys_getuid,
getxattr::{sys_fgetxattr, sys_getxattr, sys_lgetxattr},
impl_syscall_nums_and_dispatch_fn,
ioctl::sys_ioctl,
kill::sys_kill,
link::{sys_link, sys_linkat},
listen::sys_listen,
listxattr::{sys_flistxattr, sys_listxattr, sys_llistxattr},
lseek::sys_lseek,
madvise::sys_madvise,
mkdir::{sys_mkdir, sys_mkdirat},
@ -82,6 +84,7 @@ use crate::syscall::{
readlink::{sys_readlink, sys_readlinkat},
recvfrom::sys_recvfrom,
recvmsg::sys_recvmsg,
removexattr::{sys_fremovexattr, sys_lremovexattr, sys_removexattr},
rename::{sys_rename, sys_renameat},
rmdir::sys_rmdir,
rt_sigaction::sys_rt_sigaction,
@ -122,6 +125,7 @@ use crate::syscall::{
setsid::sys_setsid,
setsockopt::sys_setsockopt,
setuid::sys_setuid,
setxattr::{sys_fsetxattr, sys_lsetxattr, sys_setxattr},
shutdown::sys_shutdown,
sigaltstack::sys_sigaltstack,
signalfd::{sys_signalfd, sys_signalfd4},
@ -284,6 +288,18 @@ impl_syscall_nums_and_dispatch_fn! {
SYS_MOUNT = 165 => sys_mount(args[..5]);
SYS_UMOUNT2 = 166 => sys_umount(args[..2]);
SYS_GETTID = 186 => sys_gettid(args[..0]);
SYS_SETXATTR = 188 => sys_setxattr(args[..5]);
SYS_LSETXATTR = 189 => sys_lsetxattr(args[..5]);
SYS_FSETXATTR = 190 => sys_fsetxattr(args[..5]);
SYS_GETXATTR = 191 => sys_getxattr(args[..4]);
SYS_LGETXATTR = 192 => sys_lgetxattr(args[..4]);
SYS_FGETXATTR = 193 => sys_fgetxattr(args[..4]);
SYS_LISTXATTR = 194 => sys_listxattr(args[..3]);
SYS_LLISTXATTR = 195 => sys_llistxattr(args[..3]);
SYS_FLISTXATTR = 196 => sys_flistxattr(args[..3]);
SYS_REMOVEXATTR = 197 => sys_removexattr(args[..2]);
SYS_LREMOVEXATTR = 198 => sys_lremovexattr(args[..2]);
SYS_FREMOVEXATTR = 199 => sys_fremovexattr(args[..2]);
SYS_TIME = 201 => sys_time(args[..1]);
SYS_FUTEX = 202 => sys_futex(args[..6]);
SYS_SCHED_SETAFFINITY = 203 => sys_sched_setaffinity(args[..3]);

View File

@ -0,0 +1,103 @@
// SPDX-License-Identifier: MPL-2.0
use super::{
setxattr::{
check_xattr_namespace, lookup_dentry_for_xattr, parse_xattr_name,
read_xattr_name_cstr_from_user, XattrFileCtx,
},
SyscallReturn,
};
use crate::{
fs::{
file_table::{get_file_fast, FileDesc},
utils::XATTR_VALUE_MAX_LEN,
},
prelude::*,
syscall::constants::MAX_FILENAME_LEN,
};
pub fn sys_getxattr(
path_ptr: Vaddr,
name_ptr: Vaddr,
value_ptr: Vaddr,
value_len: usize,
ctx: &Context,
) -> Result<SyscallReturn> {
let user_space = ctx.user_space();
let path = user_space.read_cstring(path_ptr, MAX_FILENAME_LEN)?;
let len = getxattr(
XattrFileCtx::Path(path),
name_ptr,
value_ptr,
value_len,
&user_space,
ctx,
)?;
Ok(SyscallReturn::Return(len as _))
}
pub fn sys_lgetxattr(
path_ptr: Vaddr,
name_ptr: Vaddr,
value_ptr: Vaddr,
value_len: usize,
ctx: &Context,
) -> Result<SyscallReturn> {
let user_space = ctx.user_space();
let path = user_space.read_cstring(path_ptr, MAX_FILENAME_LEN)?;
let len = getxattr(
XattrFileCtx::PathNoFollow(path),
name_ptr,
value_ptr,
value_len,
&user_space,
ctx,
)?;
Ok(SyscallReturn::Return(len as _))
}
pub fn sys_fgetxattr(
fd: FileDesc,
name_ptr: Vaddr,
value_ptr: Vaddr,
value_len: usize,
ctx: &Context,
) -> Result<SyscallReturn> {
let mut file_table = ctx.thread_local.file_table().borrow_mut();
let file = get_file_fast!(&mut file_table, fd);
let user_space = ctx.user_space();
let len = getxattr(
XattrFileCtx::FileHandle(file),
name_ptr,
value_ptr,
value_len,
&user_space,
ctx,
)?;
Ok(SyscallReturn::Return(len as _))
}
fn getxattr(
file_ctx: XattrFileCtx,
name_ptr: Vaddr,
value_ptr: Vaddr,
value_len: usize,
user_space: &CurrentUserSpace,
ctx: &Context,
) -> Result<usize> {
let name_cstr = read_xattr_name_cstr_from_user(name_ptr, user_space)?;
let name_str = name_cstr.to_string_lossy();
let xattr_name = parse_xattr_name(name_str.as_ref())?;
check_xattr_namespace(xattr_name.namespace(), ctx).map_err(|_| Error::new(Errno::ENODATA))?;
let mut value_writer = user_space.writer(value_ptr, value_len.min(XATTR_VALUE_MAX_LEN))?;
let dentry = lookup_dentry_for_xattr(&file_ctx, ctx)?;
dentry.get_xattr(xattr_name, &mut value_writer)
}

View File

@ -0,0 +1,107 @@
// SPDX-License-Identifier: MPL-2.0
use super::{
setxattr::{lookup_dentry_for_xattr, XattrFileCtx},
SyscallReturn,
};
use crate::{
fs::{
file_table::{get_file_fast, FileDesc},
utils::{XattrNamespace, XATTR_LIST_MAX_LEN},
},
prelude::*,
process::credentials::capabilities::CapSet,
syscall::constants::MAX_FILENAME_LEN,
};
pub fn sys_listxattr(
path_ptr: Vaddr,
list_ptr: Vaddr, // The given list is used to place xattr (null-terminated) names.
list_len: usize,
ctx: &Context,
) -> Result<SyscallReturn> {
let user_space = ctx.user_space();
let path = user_space.read_cstring(path_ptr, MAX_FILENAME_LEN)?;
let len = listxattr(
XattrFileCtx::Path(path),
list_ptr,
list_len,
&user_space,
ctx,
)?;
Ok(SyscallReturn::Return(len as _))
}
pub fn sys_llistxattr(
path_ptr: Vaddr,
list_ptr: Vaddr, // The given list is used to place xattr (null-terminated) names.
list_len: usize,
ctx: &Context,
) -> Result<SyscallReturn> {
let user_space = ctx.user_space();
let path = user_space.read_cstring(path_ptr, MAX_FILENAME_LEN)?;
let len = listxattr(
XattrFileCtx::PathNoFollow(path),
list_ptr,
list_len,
&user_space,
ctx,
)?;
Ok(SyscallReturn::Return(len as _))
}
pub fn sys_flistxattr(
fd: FileDesc,
list_ptr: Vaddr, // The given list is used to place xattr (null-terminated) names.
list_len: usize,
ctx: &Context,
) -> Result<SyscallReturn> {
let mut file_table = ctx.thread_local.file_table().borrow_mut();
let file = get_file_fast!(&mut file_table, fd);
let user_space = ctx.user_space();
let len = listxattr(
XattrFileCtx::FileHandle(file),
list_ptr,
list_len,
&user_space,
ctx,
)?;
Ok(SyscallReturn::Return(len as _))
}
fn listxattr(
file_ctx: XattrFileCtx,
list_ptr: Vaddr,
list_len: usize,
user_space: &CurrentUserSpace,
ctx: &Context,
) -> Result<usize> {
if list_len > XATTR_LIST_MAX_LEN {
return_errno_with_message!(Errno::E2BIG, "xattr list too long");
}
let namespace = get_current_xattr_namespace(ctx);
let mut list_writer = user_space.writer(list_ptr, list_len)?;
let dentry = lookup_dentry_for_xattr(&file_ctx, ctx)?;
dentry.list_xattr(namespace, &mut list_writer)
}
fn get_current_xattr_namespace(ctx: &Context) -> XattrNamespace {
let credentials = ctx.posix_thread.credentials();
let permitted_capset = credentials.permitted_capset();
let effective_capset = credentials.effective_capset();
if permitted_capset.contains(CapSet::SYS_ADMIN) && effective_capset.contains(CapSet::SYS_ADMIN)
{
XattrNamespace::Trusted
} else {
XattrNamespace::User
}
}

View File

@ -60,10 +60,12 @@ mod getsockopt;
mod gettid;
mod gettimeofday;
mod getuid;
mod getxattr;
mod ioctl;
mod kill;
mod link;
mod listen;
mod listxattr;
mod lseek;
mod madvise;
mod mkdir;
@ -89,6 +91,7 @@ mod read;
mod readlink;
mod recvfrom;
mod recvmsg;
mod removexattr;
mod rename;
mod rmdir;
mod rt_sigaction;
@ -129,6 +132,7 @@ mod setreuid;
mod setsid;
mod setsockopt;
mod setuid;
mod setxattr;
mod shutdown;
mod sigaltstack;
mod signalfd;

View File

@ -0,0 +1,57 @@
// SPDX-License-Identifier: MPL-2.0
use super::{
setxattr::{
check_xattr_namespace, lookup_dentry_for_xattr, parse_xattr_name,
read_xattr_name_cstr_from_user, XattrFileCtx,
},
SyscallReturn,
};
use crate::{
fs::file_table::{get_file_fast, FileDesc},
prelude::*,
syscall::constants::MAX_FILENAME_LEN,
};
pub fn sys_removexattr(path_ptr: Vaddr, name_ptr: Vaddr, ctx: &Context) -> Result<SyscallReturn> {
let user_space = ctx.user_space();
let path = user_space.read_cstring(path_ptr, MAX_FILENAME_LEN)?;
removexattr(XattrFileCtx::Path(path), name_ptr, &user_space, ctx)?;
Ok(SyscallReturn::Return(0))
}
pub fn sys_lremovexattr(path_ptr: Vaddr, name_ptr: Vaddr, ctx: &Context) -> Result<SyscallReturn> {
let user_space = ctx.user_space();
let path = user_space.read_cstring(path_ptr, MAX_FILENAME_LEN)?;
removexattr(XattrFileCtx::PathNoFollow(path), name_ptr, &user_space, ctx)?;
Ok(SyscallReturn::Return(0))
}
pub fn sys_fremovexattr(fd: FileDesc, name_ptr: Vaddr, ctx: &Context) -> Result<SyscallReturn> {
let mut file_table = ctx.thread_local.file_table().borrow_mut();
let file = get_file_fast!(&mut file_table, fd);
let user_space = ctx.user_space();
removexattr(XattrFileCtx::FileHandle(file), name_ptr, &user_space, ctx)?;
Ok(SyscallReturn::Return(0))
}
fn removexattr(
file_ctx: XattrFileCtx,
name_ptr: Vaddr,
user_space: &CurrentUserSpace,
ctx: &Context,
) -> Result<()> {
let name_cstr = read_xattr_name_cstr_from_user(name_ptr, user_space)?;
let name_str = name_cstr.to_string_lossy();
let xattr_name = parse_xattr_name(name_str.as_ref())?;
check_xattr_namespace(xattr_name.namespace(), ctx)?;
let dentry = lookup_dentry_for_xattr(&file_ctx, ctx)?;
dentry.remove_xattr(xattr_name)
}

View File

@ -0,0 +1,198 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::borrow::Cow;
use super::SyscallReturn;
use crate::{
fs::{
file_handle::FileLike,
file_table::{get_file_fast, FileDesc},
fs_resolver::{FsPath, AT_FDCWD},
path::Dentry,
utils::{
XattrName, XattrNamespace, XattrSetFlags, XATTR_NAME_MAX_LEN, XATTR_VALUE_MAX_LEN,
},
},
prelude::*,
process::credentials::capabilities::CapSet,
syscall::constants::MAX_FILENAME_LEN,
};
pub fn sys_setxattr(
path_ptr: Vaddr,
name_ptr: Vaddr,
value_ptr: Vaddr,
value_len: usize,
flags: i32,
ctx: &Context,
) -> Result<SyscallReturn> {
let user_space = ctx.user_space();
let path = user_space.read_cstring(path_ptr, MAX_FILENAME_LEN)?;
setxattr(
XattrFileCtx::Path(path),
name_ptr,
value_ptr,
value_len,
flags,
&user_space,
ctx,
)?;
Ok(SyscallReturn::Return(0))
}
pub fn sys_lsetxattr(
path_ptr: Vaddr,
name_ptr: Vaddr,
value_ptr: Vaddr,
value_len: usize,
flags: i32,
ctx: &Context,
) -> Result<SyscallReturn> {
let user_space = ctx.user_space();
let path = user_space.read_cstring(path_ptr, MAX_FILENAME_LEN)?;
setxattr(
XattrFileCtx::PathNoFollow(path),
name_ptr,
value_ptr,
value_len,
flags,
&user_space,
ctx,
)?;
Ok(SyscallReturn::Return(0))
}
pub fn sys_fsetxattr(
fd: FileDesc,
name_ptr: Vaddr,
value_ptr: Vaddr,
value_len: usize,
flags: i32,
ctx: &Context,
) -> Result<SyscallReturn> {
let mut file_table = ctx.thread_local.file_table().borrow_mut();
let file = get_file_fast!(&mut file_table, fd);
let user_space = ctx.user_space();
setxattr(
XattrFileCtx::FileHandle(file),
name_ptr,
value_ptr,
value_len,
flags,
&user_space,
ctx,
)?;
Ok(SyscallReturn::Return(0))
}
fn setxattr(
file_ctx: XattrFileCtx,
name_ptr: Vaddr,
value_ptr: Vaddr,
value_len: usize,
flags: i32,
user_space: &CurrentUserSpace,
ctx: &Context,
) -> Result<()> {
let flags = XattrSetFlags::from_bits(flags as _)
.ok_or(Error::with_message(Errno::EINVAL, "invalid xattr flags"))?;
let name_cstr = read_xattr_name_cstr_from_user(name_ptr, user_space)?;
let name_str = name_cstr.to_string_lossy();
let xattr_name = parse_xattr_name(name_str.as_ref())?;
check_xattr_namespace(xattr_name.namespace(), ctx)?;
if value_len > XATTR_VALUE_MAX_LEN {
return_errno_with_message!(Errno::E2BIG, "xattr value too long");
}
let mut value_reader = user_space.reader(value_ptr, value_len)?;
let dentry = lookup_dentry_for_xattr(&file_ctx, ctx)?;
dentry.set_xattr(xattr_name, &mut value_reader, flags)
}
/// The context to describe the target file for xattr operations.
pub(super) enum XattrFileCtx<'a> {
Path(CString),
PathNoFollow(CString),
FileHandle(Cow<'a, Arc<dyn FileLike>>),
}
pub(super) fn lookup_dentry_for_xattr<'a>(
file_ctx: &'a XattrFileCtx<'a>,
ctx: &'a Context,
) -> Result<Cow<'a, Dentry>> {
let lookup_dentry_from_fs =
|path: &CString, ctx: &Context, symlink_no_follow: bool| -> Result<Cow<'_, Dentry>> {
let path = path.to_string_lossy();
let fs_path = FsPath::new(AT_FDCWD, path.as_ref())?;
let fs = ctx.posix_thread.fs().resolver().read();
let dentry = if symlink_no_follow {
fs.lookup_no_follow(&fs_path)?
} else {
fs.lookup(&fs_path)?
};
Ok(Cow::Owned(dentry))
};
match file_ctx {
XattrFileCtx::Path(path) => lookup_dentry_from_fs(path, ctx, false),
XattrFileCtx::PathNoFollow(path) => lookup_dentry_from_fs(path, ctx, true),
XattrFileCtx::FileHandle(file) => {
let dentry = file.as_inode_or_err()?.dentry();
Ok(Cow::Borrowed(dentry))
}
}
}
pub(super) fn read_xattr_name_cstr_from_user<'a>(
name_ptr: Vaddr,
user_space: &CurrentUserSpace,
) -> Result<CString> {
let mut reader = user_space.reader(name_ptr, XATTR_NAME_MAX_LEN + 1)?;
reader.read_cstring().map_err(|e| {
if reader.remain() == 0 {
Error::with_message(Errno::ERANGE, "xattr name too long")
} else {
e
}
})
}
pub(super) fn parse_xattr_name(name_str: &str) -> Result<XattrName> {
if name_str.is_empty() || name_str.len() > XATTR_NAME_MAX_LEN {
return_errno_with_message!(Errno::ERANGE, "xattr name empty or too long");
}
let xattr_name = XattrName::try_from_full_name(name_str.as_ref()).ok_or(
Error::with_message(Errno::EOPNOTSUPP, "invalid xattr namespace"),
)?;
Ok(xattr_name)
}
pub(super) fn check_xattr_namespace(namespace: XattrNamespace, ctx: &Context) -> Result<()> {
let credentials = ctx.posix_thread.credentials();
let permitted_capset = credentials.permitted_capset();
let effective_capset = credentials.effective_capset();
match namespace {
XattrNamespace::Trusted => {
if !permitted_capset.contains(CapSet::SYS_ADMIN)
|| !effective_capset.contains(CapSet::SYS_ADMIN)
{
return_errno_with_message!(
Errno::EPERM,
"try to access trusted xattr without CAP_SYS_ADMIN"
);
}
}
_ => {}
}
Ok(())
}