2018-06-06 05:42:14 +03:00
// SPDX-License-Identifier: GPL-2.0
2009-06-10 19:07:47 +04:00
/*
* Copyright ( c ) 2008 , Christoph Hellwig
* All Rights Reserved .
*/
# include "xfs.h"
2019-06-29 05:25:35 +03:00
# include "xfs_shared.h"
2013-10-23 03:51:50 +04:00
# include "xfs_format.h"
2013-08-12 14:49:23 +04:00
# include "xfs_log_format.h"
2013-08-12 14:49:32 +04:00
# include "xfs_trans_resv.h"
2013-06-05 06:09:10 +04:00
# include "xfs_mount.h"
2013-10-23 03:51:50 +04:00
# include "xfs_inode.h"
# include "xfs_attr.h"
2009-12-15 02:14:59 +03:00
# include "xfs_trace.h"
2019-11-02 19:40:53 +03:00
# include "xfs_error.h"
2019-11-07 04:19:33 +03:00
# include "xfs_acl.h"
2020-02-27 04:30:33 +03:00
# include "xfs_da_format.h"
# include "xfs_da_btree.h"
2020-12-11 07:00:39 +03:00
# include "xfs_trans.h"
2009-06-10 19:07:47 +04:00
2019-11-07 04:19:33 +03:00
# include <linux/posix_acl_xattr.h>
2009-06-10 19:07:47 +04:00
/*
* Locking scheme :
* - all ACL updates are protected by inode - > i_mutex , which is taken before
* calling into this file .
*/
STATIC struct posix_acl *
2013-06-05 06:09:10 +04:00
xfs_acl_from_disk (
2019-11-02 19:40:53 +03:00
struct xfs_mount * mp ,
2015-11-03 04:41:59 +03:00
const struct xfs_acl * aclp ,
int len ,
int max_entries )
2009-06-10 19:07:47 +04:00
{
struct posix_acl_entry * acl_e ;
struct posix_acl * acl ;
2015-11-03 04:41:59 +03:00
const struct xfs_acl_entry * ace ;
2011-12-13 01:55:52 +04:00
unsigned int count , i ;
2009-06-10 19:07:47 +04:00
2019-11-02 19:40:53 +03:00
if ( len < sizeof ( * aclp ) ) {
XFS_CORRUPTION_ERROR ( __func__ , XFS_ERRLEVEL_LOW , mp , aclp ,
len ) ;
2015-11-03 04:41:59 +03:00
return ERR_PTR ( - EFSCORRUPTED ) ;
2019-11-02 19:40:53 +03:00
}
2009-06-10 19:07:47 +04:00
count = be32_to_cpu ( aclp - > acl_cnt ) ;
2019-11-02 19:40:53 +03:00
if ( count > max_entries | | XFS_ACL_SIZE ( count ) ! = len ) {
XFS_CORRUPTION_ERROR ( __func__ , XFS_ERRLEVEL_LOW , mp , aclp ,
len ) ;
2011-11-20 19:35:32 +04:00
return ERR_PTR ( - EFSCORRUPTED ) ;
2019-11-02 19:40:53 +03:00
}
2009-06-10 19:07:47 +04:00
acl = posix_acl_alloc ( count , GFP_KERNEL ) ;
if ( ! acl )
return ERR_PTR ( - ENOMEM ) ;
for ( i = 0 ; i < count ; i + + ) {
acl_e = & acl - > a_entries [ i ] ;
ace = & aclp - > acl_entry [ i ] ;
/*
* The tag is 32 bits on disk and 16 bits in core .
*
* Because every access to it goes through the core
* format first this is not a problem .
*/
acl_e - > e_tag = be32_to_cpu ( ace - > ae_tag ) ;
acl_e - > e_perm = be16_to_cpu ( ace - > ae_perm ) ;
switch ( acl_e - > e_tag ) {
case ACL_USER :
2020-02-21 19:31:27 +03:00
acl_e - > e_uid = make_kuid ( & init_user_ns ,
be32_to_cpu ( ace - > ae_id ) ) ;
2013-08-15 22:07:59 +04:00
break ;
2009-06-10 19:07:47 +04:00
case ACL_GROUP :
2020-02-21 19:31:27 +03:00
acl_e - > e_gid = make_kgid ( & init_user_ns ,
be32_to_cpu ( ace - > ae_id ) ) ;
2009-06-10 19:07:47 +04:00
break ;
case ACL_USER_OBJ :
case ACL_GROUP_OBJ :
case ACL_MASK :
case ACL_OTHER :
break ;
default :
goto fail ;
}
}
return acl ;
fail :
posix_acl_release ( acl ) ;
return ERR_PTR ( - EINVAL ) ;
}
STATIC void
xfs_acl_to_disk ( struct xfs_acl * aclp , const struct posix_acl * acl )
{
const struct posix_acl_entry * acl_e ;
struct xfs_acl_entry * ace ;
int i ;
aclp - > acl_cnt = cpu_to_be32 ( acl - > a_count ) ;
for ( i = 0 ; i < acl - > a_count ; i + + ) {
ace = & aclp - > acl_entry [ i ] ;
acl_e = & acl - > a_entries [ i ] ;
ace - > ae_tag = cpu_to_be32 ( acl_e - > e_tag ) ;
2013-08-15 22:07:59 +04:00
switch ( acl_e - > e_tag ) {
case ACL_USER :
2020-02-21 19:31:27 +03:00
ace - > ae_id = cpu_to_be32 (
from_kuid ( & init_user_ns , acl_e - > e_uid ) ) ;
2013-08-15 22:07:59 +04:00
break ;
case ACL_GROUP :
2020-02-21 19:31:27 +03:00
ace - > ae_id = cpu_to_be32 (
from_kgid ( & init_user_ns , acl_e - > e_gid ) ) ;
2013-08-15 22:07:59 +04:00
break ;
default :
ace - > ae_id = cpu_to_be32 ( ACL_UNDEFINED_ID ) ;
break ;
}
2009-06-10 19:07:47 +04:00
ace - > ae_perm = cpu_to_be16 ( acl_e - > e_perm ) ;
}
}
struct posix_acl *
xfs_get_acl ( struct inode * inode , int type )
{
2020-02-27 04:30:34 +03:00
struct xfs_inode * ip = XFS_I ( inode ) ;
struct xfs_mount * mp = ip - > i_mount ;
struct posix_acl * acl = NULL ;
struct xfs_da_args args = {
. dp = ip ,
2020-02-27 04:30:42 +03:00
. attr_filter = XFS_ATTR_ROOT ,
2020-02-27 04:30:34 +03:00
. valuelen = XFS_ACL_MAX_SIZE ( mp ) ,
} ;
int error ;
2009-06-10 19:07:47 +04:00
2011-07-23 19:37:31 +04:00
trace_xfs_get_acl ( ip ) ;
2009-06-10 19:07:47 +04:00
switch ( type ) {
case ACL_TYPE_ACCESS :
2020-02-27 04:30:34 +03:00
args . name = SGI_ACL_FILE ;
2009-06-10 19:07:47 +04:00
break ;
case ACL_TYPE_DEFAULT :
2020-02-27 04:30:34 +03:00
args . name = SGI_ACL_DEFAULT ;
2009-06-10 19:07:47 +04:00
break ;
default :
2009-06-09 21:29:39 +04:00
BUG ( ) ;
2009-06-10 19:07:47 +04:00
}
2020-02-27 04:30:34 +03:00
args . namelen = strlen ( args . name ) ;
2009-06-10 19:07:47 +04:00
2020-02-27 04:30:35 +03:00
/*
* If the attribute doesn ' t exist make sure we have a negative cache
* entry , for any other error assume it is transient .
*/
2020-02-27 04:30:34 +03:00
error = xfs_attr_get ( & args ) ;
2020-02-27 04:30:35 +03:00
if ( ! error ) {
2020-02-27 04:30:34 +03:00
acl = xfs_acl_from_disk ( mp , args . value , args . valuelen ,
XFS_ACL_MAX_ENTRIES ( mp ) ) ;
2020-02-27 04:30:35 +03:00
} else if ( error ! = - ENOATTR ) {
acl = ERR_PTR ( error ) ;
2009-06-10 19:07:47 +04:00
}
2020-02-27 04:30:35 +03:00
kmem_free ( args . value ) ;
2009-06-10 19:07:47 +04:00
return acl ;
}
2017-06-26 18:48:18 +03:00
int
__xfs_set_acl ( struct inode * inode , struct posix_acl * acl , int type )
2009-06-10 19:07:47 +04:00
{
2020-02-27 04:30:33 +03:00
struct xfs_inode * ip = XFS_I ( inode ) ;
struct xfs_da_args args = {
. dp = ip ,
2020-02-27 04:30:42 +03:00
. attr_filter = XFS_ATTR_ROOT ,
2020-02-27 04:30:33 +03:00
} ;
int error ;
2009-06-10 19:07:47 +04:00
switch ( type ) {
case ACL_TYPE_ACCESS :
2020-02-27 04:30:33 +03:00
args . name = SGI_ACL_FILE ;
2009-06-10 19:07:47 +04:00
break ;
case ACL_TYPE_DEFAULT :
if ( ! S_ISDIR ( inode - > i_mode ) )
return acl ? - EACCES : 0 ;
2020-02-27 04:30:33 +03:00
args . name = SGI_ACL_DEFAULT ;
2009-06-10 19:07:47 +04:00
break ;
default :
return - EINVAL ;
}
2020-02-27 04:30:33 +03:00
args . namelen = strlen ( args . name ) ;
2009-06-10 19:07:47 +04:00
if ( acl ) {
2020-02-27 04:30:44 +03:00
args . valuelen = XFS_ACL_SIZE ( acl - > a_count ) ;
2020-09-01 21:47:12 +03:00
args . value = kvzalloc ( args . valuelen , GFP_KERNEL ) ;
2020-02-27 04:30:33 +03:00
if ( ! args . value )
2013-09-02 14:53:00 +04:00
return - ENOMEM ;
2020-02-27 04:30:33 +03:00
xfs_acl_to_disk ( args . value , acl ) ;
2009-06-10 19:07:47 +04:00
}
2020-02-27 04:30:33 +03:00
error = xfs_attr_set ( & args ) ;
kmem_free ( args . value ) ;
2020-02-27 04:30:29 +03:00
/*
* If the attribute didn ' t exist to start with that ' s fine .
*/
if ( ! acl & & error = = - ENOATTR )
error = 0 ;
2009-06-10 19:07:47 +04:00
if ( ! error )
2009-06-09 21:29:39 +04:00
set_cached_acl ( inode , type , acl ) ;
2009-06-10 19:07:47 +04:00
return error ;
}
static int
2020-12-11 07:00:39 +03:00
xfs_acl_set_mode (
struct inode * inode ,
umode_t mode )
2009-06-10 19:07:47 +04:00
{
2020-12-11 07:00:39 +03:00
struct xfs_inode * ip = XFS_I ( inode ) ;
struct xfs_mount * mp = ip - > i_mount ;
struct xfs_trans * tp ;
int error ;
2009-06-10 19:07:47 +04:00
2020-12-11 07:00:39 +03:00
error = xfs_trans_alloc ( mp , & M_RES ( mp ) - > tr_ichange , 0 , 0 , 0 , & tp ) ;
if ( error )
return error ;
2009-06-10 19:07:47 +04:00
2020-12-11 07:00:39 +03:00
xfs_ilock ( ip , XFS_ILOCK_EXCL ) ;
xfs_trans_ijoin ( tp , ip , XFS_ILOCK_EXCL ) ;
inode - > i_mode = mode ;
inode - > i_ctime = current_time ( inode ) ;
xfs_trans_log_inode ( tp , ip , XFS_ILOG_CORE ) ;
2009-06-10 19:07:47 +04:00
2021-08-19 04:46:52 +03:00
if ( xfs_has_wsync ( mp ) )
2020-12-11 07:00:39 +03:00
xfs_trans_set_sync ( tp ) ;
return xfs_trans_commit ( tp ) ;
2009-06-10 19:07:47 +04:00
}
int
2021-01-21 16:19:43 +03:00
xfs_set_acl ( struct user_namespace * mnt_userns , struct inode * inode ,
struct posix_acl * acl , int type )
2009-06-10 19:07:47 +04:00
{
2017-10-09 21:37:23 +03:00
umode_t mode ;
bool set_mode = false ;
2009-11-13 12:52:56 +03:00
int error = 0 ;
2009-06-10 19:07:47 +04:00
2013-12-20 17:16:50 +04:00
if ( ! acl )
2009-06-10 19:07:47 +04:00
goto set_acl ;
2014-02-07 08:26:11 +04:00
error = - E2BIG ;
2013-06-05 06:09:10 +04:00
if ( acl - > a_count > XFS_ACL_MAX_ENTRIES ( XFS_M ( inode - > i_sb ) ) )
2013-12-20 17:16:50 +04:00
return error ;
2009-06-10 19:07:47 +04:00
if ( type = = ACL_TYPE_ACCESS ) {
2021-01-21 16:19:58 +03:00
error = posix_acl_update_mode ( mnt_userns , inode , & mode , & acl ) ;
2016-09-19 18:39:09 +03:00
if ( error )
return error ;
2017-10-09 21:37:23 +03:00
set_mode = true ;
2009-06-10 19:07:47 +04:00
}
set_acl :
2017-10-09 21:37:23 +03:00
/*
* We set the mode after successfully updating the ACL xattr because the
* xattr update can fail at ENOSPC and we don ' t want to change the mode
* if the ACL update hasn ' t been applied .
*/
2020-12-11 07:00:39 +03:00
error = __xfs_set_acl ( inode , acl , type ) ;
if ( ! error & & set_mode & & mode ! = inode - > i_mode )
error = xfs_acl_set_mode ( inode , mode ) ;
2017-10-09 21:37:23 +03:00
return error ;
2009-06-10 19:07:47 +04:00
}
2020-02-27 04:30:41 +03:00
/*
* Invalidate any cached ACLs if the user has bypassed the ACL interface .
* We don ' t validate the content whatsoever so it is caller responsibility to
* provide data in valid format and ensure i_mode is consistent .
*/
void
xfs_forget_acl (
struct inode * inode ,
const char * name )
{
if ( ! strcmp ( name , SGI_ACL_FILE ) )
forget_cached_acl ( inode , ACL_TYPE_ACCESS ) ;
else if ( ! strcmp ( name , SGI_ACL_DEFAULT ) )
forget_cached_acl ( inode , ACL_TYPE_DEFAULT ) ;
}