2019-07-31 23:57:31 +08:00
// SPDX-License-Identifier: GPL-2.0-only
2018-07-26 20:21:52 +08:00
/*
* Copyright ( C ) 2017 - 2018 HUAWEI , Inc .
2020-07-13 15:09:44 +02:00
* https : //www.huawei.com/
2022-01-02 12:00:16 +08:00
* Copyright ( C ) 2021 - 2022 , Alibaba Cloud
2018-07-26 20:21:52 +08:00
*/
# include <linux/security.h>
# include "xattr.h"
2023-03-30 16:29:03 +08:00
static inline erofs_blk_t erofs_xattr_blkaddr ( struct super_block * sb ,
unsigned int xattr_id )
{
return EROFS_SB ( sb ) - > xattr_blkaddr +
erofs_blknr ( sb , xattr_id * sizeof ( __u32 ) ) ;
}
static inline unsigned int erofs_xattr_blkoff ( struct super_block * sb ,
unsigned int xattr_id )
{
return erofs_blkoff ( sb , xattr_id * sizeof ( __u32 ) ) ;
}
2018-07-26 20:21:52 +08:00
struct xattr_iter {
struct super_block * sb ;
2022-01-02 12:00:16 +08:00
struct erofs_buf buf ;
2018-07-26 20:21:52 +08:00
void * kaddr ;
erofs_blk_t blkaddr ;
2018-09-10 21:41:14 +02:00
unsigned int ofs ;
2018-07-26 20:21:52 +08:00
} ;
2023-03-30 16:29:04 +08:00
static int erofs_init_inode_xattrs ( struct inode * inode )
2018-07-26 20:21:52 +08:00
{
2019-09-04 10:08:56 +08:00
struct erofs_inode * const vi = EROFS_I ( inode ) ;
2018-07-26 20:21:52 +08:00
struct xattr_iter it ;
2018-09-10 21:41:14 +02:00
unsigned int i ;
2018-07-26 20:21:52 +08:00
struct erofs_xattr_ibody_header * ih ;
2023-01-14 23:08:23 +08:00
struct super_block * sb = inode - > i_sb ;
2019-02-18 15:19:04 +08:00
int ret = 0 ;
2018-07-26 20:21:52 +08:00
2019-02-18 15:19:04 +08:00
/* the most case is that xattrs of this inode are initialized. */
2021-02-09 21:06:18 +08:00
if ( test_bit ( EROFS_I_EA_INITED_BIT , & vi - > flags ) ) {
/*
* paired with smp_mb ( ) at the end of the function to ensure
* fields will only be observed after the bit is set .
*/
smp_mb ( ) ;
2018-08-21 22:49:31 +08:00
return 0 ;
2021-02-09 21:06:18 +08:00
}
2018-07-26 20:21:52 +08:00
2019-09-04 10:08:56 +08:00
if ( wait_on_bit_lock ( & vi - > flags , EROFS_I_BL_XATTR_BIT , TASK_KILLABLE ) )
2019-02-18 15:19:04 +08:00
return - ERESTARTSYS ;
/* someone has initialized xattrs for us? */
2019-09-04 10:08:56 +08:00
if ( test_bit ( EROFS_I_EA_INITED_BIT , & vi - > flags ) )
2019-02-18 15:19:04 +08:00
goto out_unlock ;
2019-01-14 19:40:23 +08:00
/*
* bypass all xattr operations if - > xattr_isize is not greater than
* sizeof ( struct erofs_xattr_ibody_header ) , in detail :
* 1 ) it is not enough to contain erofs_xattr_ibody_header then
* - > xattr_isize should be 0 ( it means no xattr ) ;
* 2 ) it is just to contain erofs_xattr_ibody_header , which is on - disk
* undefined right now ( maybe use later with some new sb feature ) .
*/
if ( vi - > xattr_isize = = sizeof ( struct erofs_xattr_ibody_header ) ) {
2023-01-14 23:08:23 +08:00
erofs_err ( sb ,
2019-09-04 10:09:09 +08:00
" xattr_isize %d of nid %llu is not supported yet " ,
vi - > xattr_isize , vi - > nid ) ;
2019-08-14 18:37:05 +08:00
ret = - EOPNOTSUPP ;
2019-02-18 15:19:04 +08:00
goto out_unlock ;
2019-01-14 19:40:23 +08:00
} else if ( vi - > xattr_isize < sizeof ( struct erofs_xattr_ibody_header ) ) {
2019-08-30 00:38:27 +08:00
if ( vi - > xattr_isize ) {
2023-01-14 23:08:23 +08:00
erofs_err ( sb , " bogus xattr ibody @ nid %llu " , vi - > nid ) ;
2019-01-14 19:40:23 +08:00
DBG_BUGON ( 1 ) ;
2019-08-14 18:37:03 +08:00
ret = - EFSCORRUPTED ;
2019-02-18 15:19:04 +08:00
goto out_unlock ; /* xattr ondisk layout error */
2019-01-14 19:40:23 +08:00
}
2019-02-18 15:19:04 +08:00
ret = - ENOATTR ;
goto out_unlock ;
2019-01-14 19:40:23 +08:00
}
2018-07-26 20:21:52 +08:00
2022-01-02 12:00:16 +08:00
it . buf = __EROFS_BUF_INITIALIZER ;
2023-03-13 21:53:08 +08:00
it . blkaddr = erofs_blknr ( sb , erofs_iloc ( inode ) + vi - > inode_isize ) ;
it . ofs = erofs_blkoff ( sb , erofs_iloc ( inode ) + vi - > inode_isize ) ;
2018-07-26 20:21:52 +08:00
2022-01-02 12:00:16 +08:00
/* read in shared xattr array (non-atomic, see kmalloc below) */
it . kaddr = erofs_read_metabuf ( & it . buf , sb , it . blkaddr , EROFS_KMAP ) ;
if ( IS_ERR ( it . kaddr ) ) {
ret = PTR_ERR ( it . kaddr ) ;
2019-02-18 15:19:04 +08:00
goto out_unlock ;
}
2018-07-26 20:21:52 +08:00
ih = ( struct erofs_xattr_ibody_header * ) ( it . kaddr + it . ofs ) ;
vi - > xattr_shared_count = ih - > h_shared_count ;
2018-08-21 22:49:31 +08:00
vi - > xattr_shared_xattrs = kmalloc_array ( vi - > xattr_shared_count ,
sizeof ( uint ) , GFP_KERNEL ) ;
2019-03-22 10:38:16 +08:00
if ( ! vi - > xattr_shared_xattrs ) {
2022-01-02 12:00:16 +08:00
erofs_put_metabuf ( & it . buf ) ;
2019-02-18 15:19:04 +08:00
ret = - ENOMEM ;
goto out_unlock ;
2018-08-21 22:49:31 +08:00
}
2018-07-26 20:21:52 +08:00
/* let's skip ibody header */
it . ofs + = sizeof ( struct erofs_xattr_ibody_header ) ;
for ( i = 0 ; i < vi - > xattr_shared_count ; + + i ) {
2023-03-13 21:53:08 +08:00
if ( it . ofs > = sb - > s_blocksize ) {
2018-07-26 20:21:52 +08:00
/* cannot be unaligned */
2023-03-13 21:53:08 +08:00
DBG_BUGON ( it . ofs ! = sb - > s_blocksize ) ;
2018-07-26 20:21:52 +08:00
2022-01-02 12:00:16 +08:00
it . kaddr = erofs_read_metabuf ( & it . buf , sb , + + it . blkaddr ,
EROFS_KMAP ) ;
if ( IS_ERR ( it . kaddr ) ) {
2019-02-14 14:46:36 +08:00
kfree ( vi - > xattr_shared_xattrs ) ;
vi - > xattr_shared_xattrs = NULL ;
2022-01-02 12:00:16 +08:00
ret = PTR_ERR ( it . kaddr ) ;
2019-02-18 15:19:04 +08:00
goto out_unlock ;
2019-02-14 14:46:36 +08:00
}
2018-07-26 20:21:52 +08:00
it . ofs = 0 ;
}
vi - > xattr_shared_xattrs [ i ] =
le32_to_cpu ( * ( __le32 * ) ( it . kaddr + it . ofs ) ) ;
it . ofs + = sizeof ( __le32 ) ;
}
2022-01-02 12:00:16 +08:00
erofs_put_metabuf ( & it . buf ) ;
2018-07-26 20:21:52 +08:00
2021-02-09 21:06:18 +08:00
/* paired with smp_mb() at the beginning of the function. */
smp_mb ( ) ;
2019-09-04 10:08:56 +08:00
set_bit ( EROFS_I_EA_INITED_BIT , & vi - > flags ) ;
2019-02-18 15:19:04 +08:00
out_unlock :
2019-09-04 10:08:56 +08:00
clear_and_wake_up_bit ( EROFS_I_BL_XATTR_BIT , & vi - > flags ) ;
2019-02-18 15:19:04 +08:00
return ret ;
2018-07-26 20:21:52 +08:00
}
2018-09-19 13:49:09 +08:00
/*
* the general idea for these return values is
* if 0 is returned , go on processing the current xattr ;
* 1 ( > 0 ) is returned , skip this round to process the next xattr ;
* - err ( < 0 ) is returned , an error ( maybe ENOXATTR ) occurred
* and need to be handled
*/
2018-07-26 20:21:52 +08:00
struct xattr_iter_handlers {
2019-01-08 13:24:54 +00:00
int ( * entry ) ( struct xattr_iter * _it , struct erofs_xattr_entry * entry ) ;
int ( * name ) ( struct xattr_iter * _it , unsigned int processed , char * buf ,
unsigned int len ) ;
int ( * alloc_buffer ) ( struct xattr_iter * _it , unsigned int value_sz ) ;
void ( * value ) ( struct xattr_iter * _it , unsigned int processed , char * buf ,
unsigned int len ) ;
2018-07-26 20:21:52 +08:00
} ;
2018-08-21 22:49:31 +08:00
static inline int xattr_iter_fixup ( struct xattr_iter * it )
2018-07-26 20:21:52 +08:00
{
2023-03-13 21:53:08 +08:00
if ( it - > ofs < it - > sb - > s_blocksize )
2018-08-21 22:49:31 +08:00
return 0 ;
2023-03-13 21:53:08 +08:00
it - > blkaddr + = erofs_blknr ( it - > sb , it - > ofs ) ;
2022-01-02 12:00:16 +08:00
it - > kaddr = erofs_read_metabuf ( & it - > buf , it - > sb , it - > blkaddr ,
2022-10-18 18:53:13 +08:00
EROFS_KMAP ) ;
2022-01-02 12:00:16 +08:00
if ( IS_ERR ( it - > kaddr ) )
return PTR_ERR ( it - > kaddr ) ;
2023-03-13 21:53:08 +08:00
it - > ofs = erofs_blkoff ( it - > sb , it - > ofs ) ;
2018-08-21 22:49:31 +08:00
return 0 ;
2018-07-26 20:21:52 +08:00
}
static int inline_xattr_iter_begin ( struct xattr_iter * it ,
2019-03-18 20:58:41 -03:00
struct inode * inode )
2018-07-26 20:21:52 +08:00
{
2019-09-04 10:08:56 +08:00
struct erofs_inode * const vi = EROFS_I ( inode ) ;
2018-09-10 21:41:14 +02:00
unsigned int xattr_header_sz , inline_xattr_ofs ;
2018-07-26 20:21:52 +08:00
2023-03-30 16:29:03 +08:00
xattr_header_sz = sizeof ( struct erofs_xattr_ibody_header ) +
sizeof ( u32 ) * vi - > xattr_shared_count ;
2019-08-30 00:38:27 +08:00
if ( xattr_header_sz > = vi - > xattr_isize ) {
2019-08-13 10:30:54 +08:00
DBG_BUGON ( xattr_header_sz > vi - > xattr_isize ) ;
2018-07-26 20:21:52 +08:00
return - ENOATTR ;
}
inline_xattr_ofs = vi - > inode_isize + xattr_header_sz ;
2023-03-13 21:53:08 +08:00
it - > blkaddr = erofs_blknr ( it - > sb , erofs_iloc ( inode ) + inline_xattr_ofs ) ;
it - > ofs = erofs_blkoff ( it - > sb , erofs_iloc ( inode ) + inline_xattr_ofs ) ;
2022-01-02 12:00:16 +08:00
it - > kaddr = erofs_read_metabuf ( & it - > buf , inode - > i_sb , it - > blkaddr ,
2022-10-18 18:53:13 +08:00
EROFS_KMAP ) ;
2022-01-02 12:00:16 +08:00
if ( IS_ERR ( it - > kaddr ) )
return PTR_ERR ( it - > kaddr ) ;
2018-07-26 20:21:52 +08:00
return vi - > xattr_isize - xattr_header_sz ;
}
2018-09-19 13:49:09 +08:00
/*
* Regardless of success or failure , ` xattr_foreach ' will end up with
* ` ofs ' pointing to the next xattr item rather than an arbitrary position .
*/
2018-07-26 20:21:52 +08:00
static int xattr_foreach ( struct xattr_iter * it ,
2019-03-18 20:58:41 -03:00
const struct xattr_iter_handlers * op ,
unsigned int * tlimit )
2018-07-26 20:21:52 +08:00
{
struct erofs_xattr_entry entry ;
2018-09-10 21:41:14 +02:00
unsigned int value_sz , processed , slice ;
2018-07-26 20:21:52 +08:00
int err ;
/* 0. fixup blkaddr, ofs, ipage */
2018-08-21 22:49:31 +08:00
err = xattr_iter_fixup ( it ) ;
if ( err )
return err ;
2018-07-26 20:21:52 +08:00
/*
* 1. read xattr entry to the memory ,
* since we do EROFS_XATTR_ALIGN
* therefore entry should be in the page
*/
entry = * ( struct erofs_xattr_entry * ) ( it - > kaddr + it - > ofs ) ;
2019-03-22 10:38:16 +08:00
if ( tlimit ) {
2019-09-04 10:08:50 +08:00
unsigned int entry_sz = erofs_xattr_entry_size ( & entry ) ;
2018-07-26 20:21:52 +08:00
2019-08-13 10:30:54 +08:00
/* xattr on-disk corruption: xattr entry beyond xattr_isize */
2019-08-30 00:38:27 +08:00
if ( * tlimit < entry_sz ) {
2019-08-13 10:30:54 +08:00
DBG_BUGON ( 1 ) ;
2019-08-14 18:37:03 +08:00
return - EFSCORRUPTED ;
2019-08-13 10:30:54 +08:00
}
2018-07-26 20:21:52 +08:00
* tlimit - = entry_sz ;
}
it - > ofs + = sizeof ( struct erofs_xattr_entry ) ;
value_sz = le16_to_cpu ( entry . e_value_size ) ;
/* handle entry */
err = op - > entry ( it , & entry ) ;
if ( err ) {
it - > ofs + = entry . e_name_len + value_sz ;
goto out ;
}
/* 2. handle xattr name (ofs will finally be at the end of name) */
processed = 0 ;
while ( processed < entry . e_name_len ) {
2023-03-13 21:53:08 +08:00
if ( it - > ofs > = it - > sb - > s_blocksize ) {
DBG_BUGON ( it - > ofs > it - > sb - > s_blocksize ) ;
2018-07-26 20:21:52 +08:00
2018-08-21 22:49:31 +08:00
err = xattr_iter_fixup ( it ) ;
if ( err )
goto out ;
2018-07-26 20:21:52 +08:00
it - > ofs = 0 ;
}
2023-03-13 21:53:08 +08:00
slice = min_t ( unsigned int , it - > sb - > s_blocksize - it - > ofs ,
2018-09-10 21:41:14 +02:00
entry . e_name_len - processed ) ;
2018-07-26 20:21:52 +08:00
/* handle name */
err = op - > name ( it , processed , it - > kaddr + it - > ofs , slice ) ;
if ( err ) {
it - > ofs + = entry . e_name_len - processed + value_sz ;
goto out ;
}
it - > ofs + = slice ;
processed + = slice ;
}
/* 3. handle xattr value */
processed = 0 ;
2019-03-22 10:38:16 +08:00
if ( op - > alloc_buffer ) {
2018-07-26 20:21:52 +08:00
err = op - > alloc_buffer ( it , value_sz ) ;
if ( err ) {
it - > ofs + = value_sz ;
goto out ;
}
}
while ( processed < value_sz ) {
2023-03-13 21:53:08 +08:00
if ( it - > ofs > = it - > sb - > s_blocksize ) {
DBG_BUGON ( it - > ofs > it - > sb - > s_blocksize ) ;
2018-08-21 22:49:31 +08:00
err = xattr_iter_fixup ( it ) ;
if ( err )
goto out ;
2018-07-26 20:21:52 +08:00
it - > ofs = 0 ;
}
2023-03-13 21:53:08 +08:00
slice = min_t ( unsigned int , it - > sb - > s_blocksize - it - > ofs ,
2018-09-10 21:41:14 +02:00
value_sz - processed ) ;
2018-07-26 20:21:52 +08:00
op - > value ( it , processed , it - > kaddr + it - > ofs , slice ) ;
it - > ofs + = slice ;
processed + = slice ;
}
out :
2018-09-19 13:49:09 +08:00
/* xattrs should be 4-byte aligned (on-disk constraint) */
2018-07-26 20:21:52 +08:00
it - > ofs = EROFS_XATTR_ALIGN ( it - > ofs ) ;
2018-09-19 13:49:10 +08:00
return err < 0 ? err : 0 ;
2018-07-26 20:21:52 +08:00
}
struct getxattr_iter {
struct xattr_iter it ;
char * buffer ;
2023-04-11 17:35:37 +08:00
int buffer_size , index , infix_len ;
2018-07-26 20:21:52 +08:00
struct qstr name ;
} ;
2023-04-11 17:35:37 +08:00
static int erofs_xattr_long_entrymatch ( struct getxattr_iter * it ,
struct erofs_xattr_entry * entry )
{
struct erofs_sb_info * sbi = EROFS_SB ( it - > it . sb ) ;
struct erofs_xattr_prefix_item * pf = sbi - > xattr_prefixes +
( entry - > e_name_index & EROFS_XATTR_LONG_PREFIX_MASK ) ;
if ( pf > = sbi - > xattr_prefixes + sbi - > xattr_prefix_count )
return - ENOATTR ;
if ( it - > index ! = pf - > prefix - > base_index | |
it - > name . len ! = entry - > e_name_len + pf - > infix_len )
return - ENOATTR ;
if ( memcmp ( it - > name . name , pf - > prefix - > infix , pf - > infix_len ) )
return - ENOATTR ;
it - > infix_len = pf - > infix_len ;
return 0 ;
}
2018-07-26 20:21:52 +08:00
static int xattr_entrymatch ( struct xattr_iter * _it ,
2019-03-18 20:58:41 -03:00
struct erofs_xattr_entry * entry )
2018-07-26 20:21:52 +08:00
{
struct getxattr_iter * it = container_of ( _it , struct getxattr_iter , it ) ;
2023-04-11 17:35:37 +08:00
/* should also match the infix for long name prefixes */
if ( entry - > e_name_index & EROFS_XATTR_LONG_PREFIX )
return erofs_xattr_long_entrymatch ( it , entry ) ;
if ( it - > index ! = entry - > e_name_index | |
it - > name . len ! = entry - > e_name_len )
return - ENOATTR ;
it - > infix_len = 0 ;
return 0 ;
2018-07-26 20:21:52 +08:00
}
static int xattr_namematch ( struct xattr_iter * _it ,
2019-03-18 20:58:41 -03:00
unsigned int processed , char * buf , unsigned int len )
2018-07-26 20:21:52 +08:00
{
struct getxattr_iter * it = container_of ( _it , struct getxattr_iter , it ) ;
2023-04-11 17:35:37 +08:00
if ( memcmp ( buf , it - > name . name + it - > infix_len + processed , len ) )
return - ENOATTR ;
return 0 ;
2018-07-26 20:21:52 +08:00
}
static int xattr_checkbuffer ( struct xattr_iter * _it ,
2019-03-18 20:58:41 -03:00
unsigned int value_sz )
2018-07-26 20:21:52 +08:00
{
struct getxattr_iter * it = container_of ( _it , struct getxattr_iter , it ) ;
int err = it - > buffer_size < value_sz ? - ERANGE : 0 ;
it - > buffer_size = value_sz ;
2019-03-22 10:38:16 +08:00
return ! it - > buffer ? 1 : err ;
2018-07-26 20:21:52 +08:00
}
static void xattr_copyvalue ( struct xattr_iter * _it ,
2019-03-18 20:58:41 -03:00
unsigned int processed ,
char * buf , unsigned int len )
2018-07-26 20:21:52 +08:00
{
struct getxattr_iter * it = container_of ( _it , struct getxattr_iter , it ) ;
memcpy ( it - > buffer + processed , buf , len ) ;
}
2018-08-21 22:49:31 +08:00
static const struct xattr_iter_handlers find_xattr_handlers = {
2018-07-26 20:21:52 +08:00
. entry = xattr_entrymatch ,
. name = xattr_namematch ,
. alloc_buffer = xattr_checkbuffer ,
. value = xattr_copyvalue
} ;
static int inline_getxattr ( struct inode * inode , struct getxattr_iter * it )
{
int ret ;
2018-09-10 21:41:14 +02:00
unsigned int remaining ;
2018-07-26 20:21:52 +08:00
ret = inline_xattr_iter_begin ( & it - > it , inode ) ;
if ( ret < 0 )
return ret ;
remaining = ret ;
while ( remaining ) {
2018-08-05 18:21:01 +03:00
ret = xattr_foreach ( & it - > it , & find_xattr_handlers , & remaining ) ;
2018-09-19 13:49:10 +08:00
if ( ret ! = - ENOATTR )
2018-08-21 22:49:31 +08:00
break ;
2018-07-26 20:21:52 +08:00
}
2018-09-19 13:49:10 +08:00
return ret ? ret : it - > buffer_size ;
2018-07-26 20:21:52 +08:00
}
static int shared_getxattr ( struct inode * inode , struct getxattr_iter * it )
{
2019-09-04 10:08:56 +08:00
struct erofs_inode * const vi = EROFS_I ( inode ) ;
2023-03-30 16:29:03 +08:00
struct super_block * const sb = it - > it . sb ;
unsigned int i , xsid ;
2018-07-26 20:21:52 +08:00
int ret = - ENOATTR ;
for ( i = 0 ; i < vi - > xattr_shared_count ; + + i ) {
2023-03-30 16:29:03 +08:00
xsid = vi - > xattr_shared_xattrs [ i ] ;
it - > it . blkaddr = erofs_xattr_blkaddr ( sb , xsid ) ;
it - > it . ofs = erofs_xattr_blkoff ( sb , xsid ) ;
it - > it . kaddr = erofs_read_metabuf ( & it - > it . buf , sb ,
it - > it . blkaddr , EROFS_KMAP ) ;
2022-01-02 12:00:16 +08:00
if ( IS_ERR ( it - > it . kaddr ) )
return PTR_ERR ( it - > it . kaddr ) ;
2018-07-26 20:21:52 +08:00
2018-08-05 18:21:01 +03:00
ret = xattr_foreach ( & it - > it , & find_xattr_handlers , NULL ) ;
2018-09-19 13:49:10 +08:00
if ( ret ! = - ENOATTR )
2018-08-21 22:49:31 +08:00
break ;
2018-07-26 20:21:52 +08:00
}
2018-09-19 13:49:10 +08:00
return ret ? ret : it - > buffer_size ;
2018-07-26 20:21:52 +08:00
}
static bool erofs_xattr_user_list ( struct dentry * dentry )
{
2021-10-07 15:02:23 +08:00
return test_opt ( & EROFS_SB ( dentry - > d_sb ) - > opt , XATTR_USER ) ;
2018-07-26 20:21:52 +08:00
}
static bool erofs_xattr_trusted_list ( struct dentry * dentry )
{
return capable ( CAP_SYS_ADMIN ) ;
}
int erofs_getxattr ( struct inode * inode , int index ,
2019-03-18 20:58:41 -03:00
const char * name ,
void * buffer , size_t buffer_size )
2018-07-26 20:21:52 +08:00
{
int ret ;
struct getxattr_iter it ;
2019-08-30 00:38:27 +08:00
if ( ! name )
2018-07-26 20:21:52 +08:00
return - EINVAL ;
2023-03-30 16:29:04 +08:00
ret = erofs_init_inode_xattrs ( inode ) ;
2018-08-21 22:49:31 +08:00
if ( ret )
return ret ;
2018-07-26 20:21:52 +08:00
it . index = index ;
it . name . len = strlen ( name ) ;
if ( it . name . len > EROFS_NAME_LEN )
return - ERANGE ;
2022-01-02 12:00:16 +08:00
it . it . buf = __EROFS_BUF_INITIALIZER ;
2018-07-26 20:21:52 +08:00
it . name . name = name ;
it . buffer = buffer ;
it . buffer_size = buffer_size ;
it . it . sb = inode - > i_sb ;
ret = inline_getxattr ( inode , & it ) ;
if ( ret = = - ENOATTR )
ret = shared_getxattr ( inode , & it ) ;
2022-01-02 12:00:16 +08:00
erofs_put_metabuf ( & it . it . buf ) ;
2018-07-26 20:21:52 +08:00
return ret ;
}
static int erofs_xattr_generic_get ( const struct xattr_handler * handler ,
2019-03-18 20:58:41 -03:00
struct dentry * unused , struct inode * inode ,
const char * name , void * buffer , size_t size )
2018-07-26 20:21:52 +08:00
{
2023-03-30 16:29:05 +08:00
if ( handler - > flags = = EROFS_XATTR_INDEX_USER & &
! test_opt ( & EROFS_I_SB ( inode ) - > opt , XATTR_USER ) )
return - EOPNOTSUPP ;
2018-07-26 20:21:52 +08:00
return erofs_getxattr ( inode , handler - > flags , name , buffer , size ) ;
}
const struct xattr_handler erofs_xattr_user_handler = {
. prefix = XATTR_USER_PREFIX ,
. flags = EROFS_XATTR_INDEX_USER ,
. list = erofs_xattr_user_list ,
. get = erofs_xattr_generic_get ,
} ;
const struct xattr_handler erofs_xattr_trusted_handler = {
. prefix = XATTR_TRUSTED_PREFIX ,
. flags = EROFS_XATTR_INDEX_TRUSTED ,
. list = erofs_xattr_trusted_list ,
. get = erofs_xattr_generic_get ,
} ;
# ifdef CONFIG_EROFS_FS_SECURITY
const struct xattr_handler __maybe_unused erofs_xattr_security_handler = {
. prefix = XATTR_SECURITY_PREFIX ,
. flags = EROFS_XATTR_INDEX_SECURITY ,
. get = erofs_xattr_generic_get ,
} ;
# endif
const struct xattr_handler * erofs_xattr_handlers [ ] = {
& erofs_xattr_user_handler ,
& erofs_xattr_trusted_handler ,
# ifdef CONFIG_EROFS_FS_SECURITY
& erofs_xattr_security_handler ,
# endif
NULL ,
} ;
struct listxattr_iter {
struct xattr_iter it ;
struct dentry * dentry ;
char * buffer ;
int buffer_size , buffer_ofs ;
} ;
static int xattr_entrylist ( struct xattr_iter * _it ,
2019-03-18 20:58:41 -03:00
struct erofs_xattr_entry * entry )
2018-07-26 20:21:52 +08:00
{
struct listxattr_iter * it =
container_of ( _it , struct listxattr_iter , it ) ;
2023-04-11 17:35:37 +08:00
unsigned int base_index = entry - > e_name_index ;
unsigned int prefix_len , infix_len = 0 ;
const char * prefix , * infix = NULL ;
if ( entry - > e_name_index & EROFS_XATTR_LONG_PREFIX ) {
struct erofs_sb_info * sbi = EROFS_SB ( _it - > sb ) ;
struct erofs_xattr_prefix_item * pf = sbi - > xattr_prefixes +
( entry - > e_name_index & EROFS_XATTR_LONG_PREFIX_MASK ) ;
if ( pf > = sbi - > xattr_prefixes + sbi - > xattr_prefix_count )
return 1 ;
infix = pf - > prefix - > infix ;
infix_len = pf - > infix_len ;
base_index = pf - > prefix - > base_index ;
}
2018-07-26 20:21:52 +08:00
2023-04-24 14:25:39 -07:00
prefix = erofs_xattr_prefix ( base_index , it - > dentry ) ;
2023-02-01 14:14:56 +01:00
if ( ! prefix )
2018-07-26 20:21:52 +08:00
return 1 ;
prefix_len = strlen ( prefix ) ;
2019-03-22 10:38:16 +08:00
if ( ! it - > buffer ) {
2023-04-11 17:35:37 +08:00
it - > buffer_ofs + = prefix_len + infix_len +
entry - > e_name_len + 1 ;
2018-07-26 20:21:52 +08:00
return 1 ;
}
2023-04-11 17:35:37 +08:00
if ( it - > buffer_ofs + prefix_len + infix_len +
2018-07-26 20:21:52 +08:00
+ entry - > e_name_len + 1 > it - > buffer_size )
return - ERANGE ;
memcpy ( it - > buffer + it - > buffer_ofs , prefix , prefix_len ) ;
2023-04-11 17:35:37 +08:00
memcpy ( it - > buffer + it - > buffer_ofs + prefix_len , infix , infix_len ) ;
it - > buffer_ofs + = prefix_len + infix_len ;
2018-07-26 20:21:52 +08:00
return 0 ;
}
static int xattr_namelist ( struct xattr_iter * _it ,
2019-03-18 20:58:41 -03:00
unsigned int processed , char * buf , unsigned int len )
2018-07-26 20:21:52 +08:00
{
struct listxattr_iter * it =
container_of ( _it , struct listxattr_iter , it ) ;
memcpy ( it - > buffer + it - > buffer_ofs , buf , len ) ;
it - > buffer_ofs + = len ;
return 0 ;
}
static int xattr_skipvalue ( struct xattr_iter * _it ,
2019-03-18 20:58:41 -03:00
unsigned int value_sz )
2018-07-26 20:21:52 +08:00
{
struct listxattr_iter * it =
container_of ( _it , struct listxattr_iter , it ) ;
it - > buffer [ it - > buffer_ofs + + ] = ' \0 ' ;
return 1 ;
}
2018-08-21 22:49:31 +08:00
static const struct xattr_iter_handlers list_xattr_handlers = {
2018-07-26 20:21:52 +08:00
. entry = xattr_entrylist ,
. name = xattr_namelist ,
. alloc_buffer = xattr_skipvalue ,
. value = NULL
} ;
static int inline_listxattr ( struct listxattr_iter * it )
{
int ret ;
2018-09-10 21:41:14 +02:00
unsigned int remaining ;
2018-07-26 20:21:52 +08:00
ret = inline_xattr_iter_begin ( & it - > it , d_inode ( it - > dentry ) ) ;
if ( ret < 0 )
return ret ;
remaining = ret ;
while ( remaining ) {
2018-08-05 18:21:01 +03:00
ret = xattr_foreach ( & it - > it , & list_xattr_handlers , & remaining ) ;
2018-09-19 13:49:10 +08:00
if ( ret )
2018-07-26 20:21:52 +08:00
break ;
}
2018-09-19 13:49:10 +08:00
return ret ? ret : it - > buffer_ofs ;
2018-07-26 20:21:52 +08:00
}
static int shared_listxattr ( struct listxattr_iter * it )
{
struct inode * const inode = d_inode ( it - > dentry ) ;
2019-09-04 10:08:56 +08:00
struct erofs_inode * const vi = EROFS_I ( inode ) ;
2023-03-30 16:29:03 +08:00
struct super_block * const sb = it - > it . sb ;
unsigned int i , xsid ;
2018-07-26 20:21:52 +08:00
int ret = 0 ;
for ( i = 0 ; i < vi - > xattr_shared_count ; + + i ) {
2023-03-30 16:29:03 +08:00
xsid = vi - > xattr_shared_xattrs [ i ] ;
it - > it . blkaddr = erofs_xattr_blkaddr ( sb , xsid ) ;
it - > it . ofs = erofs_xattr_blkoff ( sb , xsid ) ;
it - > it . kaddr = erofs_read_metabuf ( & it - > it . buf , sb ,
it - > it . blkaddr , EROFS_KMAP ) ;
2022-01-02 12:00:16 +08:00
if ( IS_ERR ( it - > it . kaddr ) )
return PTR_ERR ( it - > it . kaddr ) ;
2018-07-26 20:21:52 +08:00
2018-08-05 18:21:01 +03:00
ret = xattr_foreach ( & it - > it , & list_xattr_handlers , NULL ) ;
2018-09-19 13:49:10 +08:00
if ( ret )
2018-07-26 20:21:52 +08:00
break ;
}
2018-09-19 13:49:10 +08:00
return ret ? ret : it - > buffer_ofs ;
2018-07-26 20:21:52 +08:00
}
ssize_t erofs_listxattr ( struct dentry * dentry ,
2019-03-18 20:58:41 -03:00
char * buffer , size_t buffer_size )
2018-07-26 20:21:52 +08:00
{
int ret ;
struct listxattr_iter it ;
2023-03-30 16:29:04 +08:00
ret = erofs_init_inode_xattrs ( d_inode ( dentry ) ) ;
2019-12-01 16:01:09 +08:00
if ( ret = = - ENOATTR )
return 0 ;
2018-08-21 22:49:31 +08:00
if ( ret )
return ret ;
2018-07-26 20:21:52 +08:00
2022-01-02 12:00:16 +08:00
it . it . buf = __EROFS_BUF_INITIALIZER ;
2018-07-26 20:21:52 +08:00
it . dentry = dentry ;
it . buffer = buffer ;
it . buffer_size = buffer_size ;
it . buffer_ofs = 0 ;
it . it . sb = dentry - > d_sb ;
ret = inline_listxattr ( & it ) ;
2022-01-02 12:00:16 +08:00
if ( ret > = 0 | | ret = = - ENOATTR )
ret = shared_listxattr ( & it ) ;
erofs_put_metabuf ( & it . it . buf ) ;
return ret ;
2018-07-26 20:21:52 +08:00
}
2023-04-07 22:17:08 +08:00
void erofs_xattr_prefixes_cleanup ( struct super_block * sb )
{
struct erofs_sb_info * sbi = EROFS_SB ( sb ) ;
int i ;
if ( sbi - > xattr_prefixes ) {
for ( i = 0 ; i < sbi - > xattr_prefix_count ; i + + )
kfree ( sbi - > xattr_prefixes [ i ] . prefix ) ;
kfree ( sbi - > xattr_prefixes ) ;
sbi - > xattr_prefixes = NULL ;
}
}
int erofs_xattr_prefixes_init ( struct super_block * sb )
{
struct erofs_sb_info * sbi = EROFS_SB ( sb ) ;
struct erofs_buf buf = __EROFS_BUF_INITIALIZER ;
erofs_off_t pos = ( erofs_off_t ) sbi - > xattr_prefix_start < < 2 ;
struct erofs_xattr_prefix_item * pfs ;
int ret = 0 , i , len ;
if ( ! sbi - > xattr_prefix_count )
return 0 ;
pfs = kzalloc ( sbi - > xattr_prefix_count * sizeof ( * pfs ) , GFP_KERNEL ) ;
if ( ! pfs )
return - ENOMEM ;
2023-05-15 18:39:41 +08:00
if ( sbi - > packed_inode )
2023-04-07 22:17:08 +08:00
buf . inode = sbi - > packed_inode ;
else
erofs_init_metabuf ( & buf , sb ) ;
for ( i = 0 ; i < sbi - > xattr_prefix_count ; i + + ) {
void * ptr = erofs_read_metadata ( sb , & buf , & pos , & len ) ;
if ( IS_ERR ( ptr ) ) {
ret = PTR_ERR ( ptr ) ;
break ;
} else if ( len < sizeof ( * pfs - > prefix ) | |
len > EROFS_NAME_LEN + sizeof ( * pfs - > prefix ) ) {
kfree ( ptr ) ;
ret = - EFSCORRUPTED ;
break ;
}
pfs [ i ] . prefix = ptr ;
pfs [ i ] . infix_len = len - sizeof ( struct erofs_xattr_long_prefix ) ;
}
erofs_put_metabuf ( & buf ) ;
sbi - > xattr_prefixes = pfs ;
if ( ret )
erofs_xattr_prefixes_cleanup ( sb ) ;
return ret ;
}
2019-01-29 16:35:20 +08:00
# ifdef CONFIG_EROFS_FS_POSIX_ACL
2021-08-18 22:08:24 +02:00
struct posix_acl * erofs_get_acl ( struct inode * inode , int type , bool rcu )
2019-01-29 16:35:20 +08:00
{
struct posix_acl * acl ;
int prefix , rc ;
char * value = NULL ;
2021-08-18 22:08:24 +02:00
if ( rcu )
return ERR_PTR ( - ECHILD ) ;
2019-01-29 16:35:20 +08:00
switch ( type ) {
case ACL_TYPE_ACCESS :
prefix = EROFS_XATTR_INDEX_POSIX_ACL_ACCESS ;
break ;
case ACL_TYPE_DEFAULT :
prefix = EROFS_XATTR_INDEX_POSIX_ACL_DEFAULT ;
break ;
default :
return ERR_PTR ( - EINVAL ) ;
}
rc = erofs_getxattr ( inode , prefix , " " , NULL , 0 ) ;
if ( rc > 0 ) {
value = kmalloc ( rc , GFP_KERNEL ) ;
if ( ! value )
return ERR_PTR ( - ENOMEM ) ;
rc = erofs_getxattr ( inode , prefix , " " , value , rc ) ;
}
if ( rc = = - ENOATTR )
acl = NULL ;
else if ( rc < 0 )
acl = ERR_PTR ( rc ) ;
else
acl = posix_acl_from_xattr ( & init_user_ns , value , rc ) ;
kfree ( value ) ;
return acl ;
}
# endif