2021-03-16 04:49:09 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright ( C ) 2021 Samsung Electronics Co . , Ltd .
* Author ( s ) : Namjae Jeon < linkinjeon @ kernel . org >
*/
# include <linux/fs.h>
# include "glob.h"
# include "ndr.h"
2021-06-25 01:02:09 +03:00
static inline char * ndr_get_field ( struct ndr * n )
{
return n - > data + n - > offset ;
}
2021-03-16 04:49:09 +03:00
static int try_to_realloc_ndr_blob ( struct ndr * n , size_t sz )
{
char * data ;
data = krealloc ( n - > data , n - > offset + sz + 1024 , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
n - > data = data ;
n - > length + = 1024 ;
memset ( n - > data + n - > offset , 0 , 1024 ) ;
return 0 ;
}
2021-09-03 01:09:44 +03:00
static int ndr_write_int16 ( struct ndr * n , __u16 value )
2021-03-16 04:49:09 +03:00
{
2021-09-03 01:09:44 +03:00
if ( n - > length < = n - > offset + sizeof ( value ) ) {
int ret ;
ret = try_to_realloc_ndr_blob ( n , sizeof ( value ) ) ;
if ( ret )
return ret ;
}
2021-03-16 04:49:09 +03:00
2021-06-25 01:02:09 +03:00
* ( __le16 * ) ndr_get_field ( n ) = cpu_to_le16 ( value ) ;
2021-03-16 04:49:09 +03:00
n - > offset + = sizeof ( value ) ;
2021-09-03 01:09:44 +03:00
return 0 ;
2021-03-16 04:49:09 +03:00
}
2021-09-03 01:09:44 +03:00
static int ndr_write_int32 ( struct ndr * n , __u32 value )
2021-03-16 04:49:09 +03:00
{
2021-09-03 01:09:44 +03:00
if ( n - > length < = n - > offset + sizeof ( value ) ) {
int ret ;
ret = try_to_realloc_ndr_blob ( n , sizeof ( value ) ) ;
if ( ret )
return ret ;
}
2021-03-16 04:49:09 +03:00
2021-06-25 01:02:09 +03:00
* ( __le32 * ) ndr_get_field ( n ) = cpu_to_le32 ( value ) ;
2021-03-16 04:49:09 +03:00
n - > offset + = sizeof ( value ) ;
2021-09-03 01:09:44 +03:00
return 0 ;
2021-03-16 04:49:09 +03:00
}
2021-09-03 01:09:44 +03:00
static int ndr_write_int64 ( struct ndr * n , __u64 value )
2021-03-16 04:49:09 +03:00
{
2021-09-03 01:09:44 +03:00
if ( n - > length < = n - > offset + sizeof ( value ) ) {
int ret ;
ret = try_to_realloc_ndr_blob ( n , sizeof ( value ) ) ;
if ( ret )
return ret ;
}
2021-03-16 04:49:09 +03:00
2021-06-25 01:02:09 +03:00
* ( __le64 * ) ndr_get_field ( n ) = cpu_to_le64 ( value ) ;
2021-03-16 04:49:09 +03:00
n - > offset + = sizeof ( value ) ;
2021-09-03 01:09:44 +03:00
return 0 ;
2021-03-16 04:49:09 +03:00
}
static int ndr_write_bytes ( struct ndr * n , void * value , size_t sz )
{
2021-09-03 01:09:44 +03:00
if ( n - > length < = n - > offset + sz ) {
int ret ;
ret = try_to_realloc_ndr_blob ( n , sz ) ;
if ( ret )
return ret ;
}
2021-03-16 04:49:09 +03:00
2021-06-25 01:02:09 +03:00
memcpy ( ndr_get_field ( n ) , value , sz ) ;
2021-03-16 04:49:09 +03:00
n - > offset + = sz ;
return 0 ;
}
2021-07-23 07:01:06 +03:00
static int ndr_write_string ( struct ndr * n , char * value )
2021-03-16 04:49:09 +03:00
{
2021-07-23 07:01:06 +03:00
size_t sz ;
sz = strlen ( value ) + 1 ;
2021-09-03 01:09:44 +03:00
if ( n - > length < = n - > offset + sz ) {
int ret ;
ret = try_to_realloc_ndr_blob ( n , sz ) ;
if ( ret )
return ret ;
}
2021-03-16 04:49:09 +03:00
2021-07-23 07:01:06 +03:00
memcpy ( ndr_get_field ( n ) , value , sz ) ;
2021-03-16 04:49:09 +03:00
n - > offset + = sz ;
2021-06-25 01:02:08 +03:00
n - > offset = ALIGN ( n - > offset , 2 ) ;
2021-03-16 04:49:09 +03:00
return 0 ;
}
static int ndr_read_string ( struct ndr * n , void * value , size_t sz )
{
2021-09-03 01:09:44 +03:00
int len ;
2021-03-16 04:49:09 +03:00
2021-09-03 01:09:44 +03:00
if ( n - > offset + sz > n - > length )
return - EINVAL ;
len = strnlen ( ndr_get_field ( n ) , sz ) ;
if ( value )
memcpy ( value , ndr_get_field ( n ) , len ) ;
2021-03-16 04:49:09 +03:00
len + + ;
n - > offset + = len ;
2021-06-25 01:02:08 +03:00
n - > offset = ALIGN ( n - > offset , 2 ) ;
2021-03-16 04:49:09 +03:00
return 0 ;
}
static int ndr_read_bytes ( struct ndr * n , void * value , size_t sz )
{
2021-09-03 01:09:44 +03:00
if ( n - > offset + sz > n - > length )
return - EINVAL ;
if ( value )
memcpy ( value , ndr_get_field ( n ) , sz ) ;
2021-03-16 04:49:09 +03:00
n - > offset + = sz ;
return 0 ;
}
2021-09-03 01:09:44 +03:00
static int ndr_read_int16 ( struct ndr * n , __u16 * value )
2021-03-16 04:49:09 +03:00
{
2021-09-03 01:09:44 +03:00
if ( n - > offset + sizeof ( __u16 ) > n - > length )
return - EINVAL ;
2021-03-16 04:49:09 +03:00
2021-09-03 01:09:44 +03:00
if ( value )
* value = le16_to_cpu ( * ( __le16 * ) ndr_get_field ( n ) ) ;
2021-03-16 04:49:09 +03:00
n - > offset + = sizeof ( __u16 ) ;
2021-09-03 01:09:44 +03:00
return 0 ;
2021-03-16 04:49:09 +03:00
}
2021-09-03 01:09:44 +03:00
static int ndr_read_int32 ( struct ndr * n , __u32 * value )
2021-03-16 04:49:09 +03:00
{
2021-09-03 01:09:44 +03:00
if ( n - > offset + sizeof ( __u32 ) > n - > length )
2021-11-30 15:50:47 +03:00
return - EINVAL ;
2021-03-16 04:49:09 +03:00
2021-09-03 01:09:44 +03:00
if ( value )
* value = le32_to_cpu ( * ( __le32 * ) ndr_get_field ( n ) ) ;
2021-03-16 04:49:09 +03:00
n - > offset + = sizeof ( __u32 ) ;
2021-09-03 01:09:44 +03:00
return 0 ;
2021-03-16 04:49:09 +03:00
}
2021-09-03 01:09:44 +03:00
static int ndr_read_int64 ( struct ndr * n , __u64 * value )
2021-03-16 04:49:09 +03:00
{
2021-09-03 01:09:44 +03:00
if ( n - > offset + sizeof ( __u64 ) > n - > length )
return - EINVAL ;
2021-03-16 04:49:09 +03:00
2021-09-03 01:09:44 +03:00
if ( value )
* value = le64_to_cpu ( * ( __le64 * ) ndr_get_field ( n ) ) ;
2021-03-16 04:49:09 +03:00
n - > offset + = sizeof ( __u64 ) ;
2021-09-03 01:09:44 +03:00
return 0 ;
2021-03-16 04:49:09 +03:00
}
int ndr_encode_dos_attr ( struct ndr * n , struct xattr_dos_attrib * da )
{
char hex_attr [ 12 ] = { 0 } ;
2021-09-03 01:09:44 +03:00
int ret ;
2021-03-16 04:49:09 +03:00
n - > offset = 0 ;
n - > length = 1024 ;
n - > data = kzalloc ( n - > length , GFP_KERNEL ) ;
if ( ! n - > data )
return - ENOMEM ;
if ( da - > version = = 3 ) {
snprintf ( hex_attr , 10 , " 0x%x " , da - > attr ) ;
2021-09-03 01:09:44 +03:00
ret = ndr_write_string ( n , hex_attr ) ;
2021-03-16 04:49:09 +03:00
} else {
2021-09-03 01:09:44 +03:00
ret = ndr_write_string ( n , " " ) ;
2021-03-16 04:49:09 +03:00
}
2021-09-03 01:09:44 +03:00
if ( ret )
return ret ;
ret = ndr_write_int16 ( n , da - > version ) ;
if ( ret )
return ret ;
ret = ndr_write_int32 ( n , da - > version ) ;
if ( ret )
return ret ;
ret = ndr_write_int32 ( n , da - > flags ) ;
if ( ret )
return ret ;
ret = ndr_write_int32 ( n , da - > attr ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
if ( da - > version = = 3 ) {
2021-09-03 01:09:44 +03:00
ret = ndr_write_int32 ( n , da - > ea_size ) ;
if ( ret )
return ret ;
ret = ndr_write_int64 ( n , da - > size ) ;
if ( ret )
return ret ;
ret = ndr_write_int64 ( n , da - > alloc_size ) ;
2021-03-30 08:25:35 +03:00
} else {
2021-09-03 01:09:44 +03:00
ret = ndr_write_int64 ( n , da - > itime ) ;
2021-03-30 08:25:35 +03:00
}
2021-09-03 01:09:44 +03:00
if ( ret )
return ret ;
ret = ndr_write_int64 ( n , da - > create_time ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
if ( da - > version = = 3 )
2021-09-03 01:09:44 +03:00
ret = ndr_write_int64 ( n , da - > change_time ) ;
return ret ;
2021-03-16 04:49:09 +03:00
}
int ndr_decode_dos_attr ( struct ndr * n , struct xattr_dos_attrib * da )
{
2021-09-03 01:09:44 +03:00
char hex_attr [ 12 ] ;
unsigned int version2 ;
int ret ;
ksmbd: fix __write_overflow warning in ndr_read_string
Dan reported __write_overflow warning in ndr_read_string.
CC [M] fs/ksmbd/ndr.o
In file included from ./include/linux/string.h:253,
from ./include/linux/bitmap.h:11,
from ./include/linux/cpumask.h:12,
from ./arch/x86/include/asm/cpumask.h:5,
from ./arch/x86/include/asm/msr.h:11,
from ./arch/x86/include/asm/processor.h:22,
from ./arch/x86/include/asm/cpufeature.h:5,
from ./arch/x86/include/asm/thread_info.h:53,
from ./include/linux/thread_info.h:60,
from ./arch/x86/include/asm/preempt.h:7,
from ./include/linux/preempt.h:78,
from ./include/linux/spinlock.h:55,
from ./include/linux/wait.h:9,
from ./include/linux/wait_bit.h:8,
from ./include/linux/fs.h:6,
from fs/ksmbd/ndr.c:7:
In function memcpy,
inlined from ndr_read_string at fs/ksmbd/ndr.c:86:2,
inlined from ndr_decode_dos_attr at fs/ksmbd/ndr.c:167:2:
./include/linux/fortify-string.h:219:4: error: call to __write_overflow
declared with attribute error: detected write beyond size of object
__write_overflow();
^~~~~~~~~~~~~~~~~~
This seems to be a false alarm because hex_attr size is always smaller
than n->length. This patch fix this warning by allocation hex_attr with
n->length.
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
2021-08-27 04:18:05 +03:00
2021-03-16 04:49:09 +03:00
n - > offset = 0 ;
2021-09-03 01:09:44 +03:00
ret = ndr_read_string ( n , hex_attr , sizeof ( hex_attr ) ) ;
if ( ret )
return ret ;
ret = ndr_read_int16 ( n , & da - > version ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
if ( da - > version ! = 3 & & da - > version ! = 4 ) {
2021-06-28 09:23:19 +03:00
pr_err ( " v%d version is not supported \n " , da - > version ) ;
2021-03-16 04:49:09 +03:00
return - EINVAL ;
}
2021-09-03 01:09:44 +03:00
ret = ndr_read_int32 ( n , & version2 ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
if ( da - > version ! = version2 ) {
2021-06-28 09:23:19 +03:00
pr_err ( " ndr version mismatched(version: %d, version2: %d) \n " ,
da - > version , version2 ) ;
2021-03-16 04:49:09 +03:00
return - EINVAL ;
}
2021-09-03 01:09:44 +03:00
ret = ndr_read_int32 ( n , NULL ) ;
if ( ret )
return ret ;
ret = ndr_read_int32 ( n , & da - > attr ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
if ( da - > version = = 4 ) {
2021-09-03 01:09:44 +03:00
ret = ndr_read_int64 ( n , & da - > itime ) ;
if ( ret )
return ret ;
ret = ndr_read_int64 ( n , & da - > create_time ) ;
2021-03-16 04:49:09 +03:00
} else {
2021-09-03 01:09:44 +03:00
ret = ndr_read_int32 ( n , NULL ) ;
if ( ret )
return ret ;
2021-09-06 16:44:38 +03:00
ret = ndr_read_int64 ( n , NULL ) ;
2021-09-03 01:09:44 +03:00
if ( ret )
return ret ;
2021-09-06 16:44:38 +03:00
ret = ndr_read_int64 ( n , NULL ) ;
2021-09-03 01:09:44 +03:00
if ( ret )
return ret ;
ret = ndr_read_int64 ( n , & da - > create_time ) ;
if ( ret )
return ret ;
ret = ndr_read_int64 ( n , NULL ) ;
2021-03-16 04:49:09 +03:00
}
2021-09-03 01:09:44 +03:00
return ret ;
2021-03-16 04:49:09 +03:00
}
static int ndr_encode_posix_acl_entry ( struct ndr * n , struct xattr_smb_acl * acl )
{
2021-09-03 01:09:44 +03:00
int i , ret ;
ret = ndr_write_int32 ( n , acl - > count ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
2021-06-25 01:02:08 +03:00
n - > offset = ALIGN ( n - > offset , 8 ) ;
2021-09-03 01:09:44 +03:00
ret = ndr_write_int32 ( n , acl - > count ) ;
if ( ret )
return ret ;
ret = ndr_write_int32 ( n , 0 ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
for ( i = 0 ; i < acl - > count ; i + + ) {
2021-06-25 01:02:08 +03:00
n - > offset = ALIGN ( n - > offset , 8 ) ;
2021-09-03 01:09:44 +03:00
ret = ndr_write_int16 ( n , acl - > entries [ i ] . type ) ;
if ( ret )
return ret ;
ret = ndr_write_int16 ( n , acl - > entries [ i ] . type ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
if ( acl - > entries [ i ] . type = = SMB_ACL_USER ) {
2021-06-25 01:02:08 +03:00
n - > offset = ALIGN ( n - > offset , 8 ) ;
2021-09-03 01:09:44 +03:00
ret = ndr_write_int64 ( n , acl - > entries [ i ] . uid ) ;
2021-03-16 04:49:09 +03:00
} else if ( acl - > entries [ i ] . type = = SMB_ACL_GROUP ) {
2021-06-25 01:02:08 +03:00
n - > offset = ALIGN ( n - > offset , 8 ) ;
2021-09-03 01:09:44 +03:00
ret = ndr_write_int64 ( n , acl - > entries [ i ] . gid ) ;
2021-03-16 04:49:09 +03:00
}
2021-09-03 01:09:44 +03:00
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
/* push permission */
2021-09-03 01:09:44 +03:00
ret = ndr_write_int32 ( n , acl - > entries [ i ] . perm ) ;
2021-03-16 04:49:09 +03:00
}
2021-09-03 01:09:44 +03:00
return ret ;
2021-03-16 04:49:09 +03:00
}
2021-06-30 12:25:53 +03:00
int ndr_encode_posix_acl ( struct ndr * n ,
struct user_namespace * user_ns ,
struct inode * inode ,
2021-05-26 11:57:12 +03:00
struct xattr_smb_acl * acl ,
struct xattr_smb_acl * def_acl )
2021-03-16 04:49:09 +03:00
{
2021-09-03 01:09:44 +03:00
unsigned int ref_id = 0x00020000 ;
int ret ;
2021-03-16 04:49:09 +03:00
n - > offset = 0 ;
n - > length = 1024 ;
n - > data = kzalloc ( n - > length , GFP_KERNEL ) ;
if ( ! n - > data )
return - ENOMEM ;
if ( acl ) {
/* ACL ACCESS */
2021-09-03 01:09:44 +03:00
ret = ndr_write_int32 ( n , ref_id ) ;
2021-03-16 04:49:09 +03:00
ref_id + = 4 ;
2021-03-30 08:25:35 +03:00
} else {
2021-09-03 01:09:44 +03:00
ret = ndr_write_int32 ( n , 0 ) ;
2021-03-30 08:25:35 +03:00
}
2021-09-03 01:09:44 +03:00
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
if ( def_acl ) {
/* DEFAULT ACL ACCESS */
2021-09-03 01:09:44 +03:00
ret = ndr_write_int32 ( n , ref_id ) ;
2021-03-16 04:49:09 +03:00
ref_id + = 4 ;
2021-03-30 08:25:35 +03:00
} else {
2021-09-03 01:09:44 +03:00
ret = ndr_write_int32 ( n , 0 ) ;
2021-03-30 08:25:35 +03:00
}
2021-09-03 01:09:44 +03:00
if ( ret )
return ret ;
ret = ndr_write_int64 ( n , from_kuid ( & init_user_ns , i_uid_into_mnt ( user_ns , inode ) ) ) ;
if ( ret )
return ret ;
ret = ndr_write_int64 ( n , from_kgid ( & init_user_ns , i_gid_into_mnt ( user_ns , inode ) ) ) ;
if ( ret )
return ret ;
ret = ndr_write_int32 ( n , inode - > i_mode ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
if ( acl ) {
2021-09-03 01:09:44 +03:00
ret = ndr_encode_posix_acl_entry ( n , acl ) ;
if ( def_acl & & ! ret )
ret = ndr_encode_posix_acl_entry ( n , def_acl ) ;
2021-03-16 04:49:09 +03:00
}
2021-09-03 01:09:44 +03:00
return ret ;
2021-03-16 04:49:09 +03:00
}
int ndr_encode_v4_ntacl ( struct ndr * n , struct xattr_ntacl * acl )
{
2021-09-03 01:09:44 +03:00
unsigned int ref_id = 0x00020004 ;
int ret ;
2021-03-16 04:49:09 +03:00
n - > offset = 0 ;
n - > length = 2048 ;
n - > data = kzalloc ( n - > length , GFP_KERNEL ) ;
if ( ! n - > data )
return - ENOMEM ;
2021-09-03 01:09:44 +03:00
ret = ndr_write_int16 ( n , acl - > version ) ;
if ( ret )
return ret ;
ret = ndr_write_int32 ( n , acl - > version ) ;
if ( ret )
return ret ;
ret = ndr_write_int16 ( n , 2 ) ;
if ( ret )
return ret ;
ret = ndr_write_int32 ( n , ref_id ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
/* push hash type and hash 64bytes */
2021-09-03 01:09:44 +03:00
ret = ndr_write_int16 ( n , acl - > hash_type ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
2021-09-03 01:09:44 +03:00
ret = ndr_write_bytes ( n , acl - > hash , XATTR_SD_HASH_SIZE ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
2021-09-03 01:09:44 +03:00
ret = ndr_write_bytes ( n , acl - > desc , acl - > desc_len ) ;
if ( ret )
return ret ;
ret = ndr_write_int64 ( n , acl - > current_time ) ;
if ( ret )
return ret ;
ret = ndr_write_bytes ( n , acl - > posix_acl_hash , XATTR_SD_HASH_SIZE ) ;
if ( ret )
return ret ;
/* push ndr for security descriptor */
ret = ndr_write_bytes ( n , acl - > sd_buf , acl - > sd_size ) ;
return ret ;
2021-03-16 04:49:09 +03:00
}
int ndr_decode_v4_ntacl ( struct ndr * n , struct xattr_ntacl * acl )
{
2021-09-03 01:09:44 +03:00
unsigned int version2 ;
int ret ;
2021-03-16 04:49:09 +03:00
n - > offset = 0 ;
2021-09-03 01:09:44 +03:00
ret = ndr_read_int16 ( n , & acl - > version ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
if ( acl - > version ! = 4 ) {
2021-06-28 09:23:19 +03:00
pr_err ( " v%d version is not supported \n " , acl - > version ) ;
2021-03-16 04:49:09 +03:00
return - EINVAL ;
}
2021-09-03 01:09:44 +03:00
ret = ndr_read_int32 ( n , & version2 ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
if ( acl - > version ! = version2 ) {
2021-06-28 09:23:19 +03:00
pr_err ( " ndr version mismatched(version: %d, version2: %d) \n " ,
acl - > version , version2 ) ;
2021-03-16 04:49:09 +03:00
return - EINVAL ;
}
/* Read Level */
2021-09-03 01:09:44 +03:00
ret = ndr_read_int16 ( n , NULL ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
/* Read Ref Id */
2021-09-03 01:09:44 +03:00
ret = ndr_read_int32 ( n , NULL ) ;
if ( ret )
return ret ;
ret = ndr_read_int16 ( n , & acl - > hash_type ) ;
if ( ret )
return ret ;
ret = ndr_read_bytes ( n , acl - > hash , XATTR_SD_HASH_SIZE ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
ndr_read_bytes ( n , acl - > desc , 10 ) ;
if ( strncmp ( acl - > desc , " posix_acl " , 9 ) ) {
2021-06-28 09:23:19 +03:00
pr_err ( " Invalid acl description : %s \n " , acl - > desc ) ;
2021-03-16 04:49:09 +03:00
return - EINVAL ;
}
/* Read Time */
2021-09-03 01:09:44 +03:00
ret = ndr_read_int64 ( n , NULL ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
/* Read Posix ACL hash */
2021-09-03 01:09:44 +03:00
ret = ndr_read_bytes ( n , acl - > posix_acl_hash , XATTR_SD_HASH_SIZE ) ;
if ( ret )
return ret ;
2021-03-16 04:49:09 +03:00
acl - > sd_size = n - > length - n - > offset ;
acl - > sd_buf = kzalloc ( acl - > sd_size , GFP_KERNEL ) ;
if ( ! acl - > sd_buf )
return - ENOMEM ;
2021-09-03 01:09:44 +03:00
ret = ndr_read_bytes ( n , acl - > sd_buf , acl - > sd_size ) ;
return ret ;
2021-03-16 04:49:09 +03:00
}