From: liaohua This patch provides security namespace xattr support for Yaffs2. Adjust the yaffs2 to use the generic xattr handler by replace yaffs_setxattr with generic_setxattr in yaffs_file_inode_operations. And we add yaffs_security_xattr_handler for security namespace xattr support. We have tested the basic functions, for example, set and get the capabilities of some file like ping. And a file named security_xattr_ping.sh is provided as a test script. Thanks in advance for any advice you can provide. Signed-off-by: liaohua --- Makefile | 1 + Makefile.kernel | 1 + linux-tests/security_xattr_ping.sh | 151 +++++++++++++++++++++++++++++ yaffs_guts.h | 4 + yaffs_nameval.c | 39 ++++---- yaffs_security.c | 87 +++++++++++++++++ yaffs_vfs_multi.c | 119 ++++++++++++++++++----- yaffs_xattr.h | 40 ++++++++ 8 files changed, 398 insertions(+), 44 deletions(-) create mode 100644 linux-tests/security_xattr_ping.sh create mode 100644 yaffs_security.c create mode 100644 yaffs_xattr.h diff --git a/Makefile b/Makefile index 9318d4d..509c306 100644 --- a/Makefile +++ b/Makefile @@ -55,6 +55,7 @@ ifneq ($(KERNELRELEASE),) yaffs2multi-objs += yaffs_verify.o yaffs2multi-objs += yaffs_endian.o yaffs2multi-objs += yaffs_summary.o + yaffs2multi-objs += yaffs_security.o else KERNELDIR ?= /lib/modules/$(shell uname -r)/build diff --git a/Makefile.kernel b/Makefile.kernel index c052395..e842883 100644 --- a/Makefile.kernel +++ b/Makefile.kernel @@ -16,4 +16,5 @@ yaffs-y += yaffs_yaffs2.o yaffs-y += yaffs_bitmap.o yaffs-y += yaffs_summary.o yaffs-y += yaffs_verify.o +yaffs-y += yaffs_security.o diff --git a/linux-tests/security_xattr_ping.sh b/linux-tests/security_xattr_ping.sh new file mode 100644 index 0000000..42a9fd1 --- /dev/null +++ b/linux-tests/security_xattr_ping.sh @@ -0,0 +1,151 @@ +#!/bin/bash + +pre_test() { + mount | grep yaffs2 + if [ $? -ne 0 ]; then + echo "ERROR: no yaffs2 filesystem was mounted." + return 1 + fi + yaffs_dir=$(mount | grep yaffs2 | awk -F " " '{print $3}') + echo $yaffs_dir + + which ping + if [ $? -ne 0 ]; then + echo "ERROR: no ping exist." + return 1 + fi + ping_dir=$(which ping) + echo $ping_dir +} + +setcap_net_ping_test() { + cd $yaffs_dir + if [ $? -ne 0 ]; then + echo "Error: yaffs2 dir not fount" + return 1 + fi + + cp $ping_dir ./ + chmod 755 ping + ls -al ping | grep rws + if [ $? -eq 0 ]; then + chmod -s ping + fi + + ./ping 127.0.0.1 -c 3 + if [ $? -ne 0 ]; then + echo "ERROR: ping 127.0.0.1 fail" + return 1 + fi + + # Add normal user; + useradd -m yaffs_test + echo "Yaffs2 xattr test: su yaffs_test and ping again." + su yaffs_test -c "cd $yaffs_dir && ./ping 127.0.0.1 -c 3" + if [ $? -eq 0 ]; then + echo "ERROR: yaffs_test ping 127.0.0.1 success, test fail" + return 1 + fi + + setcap 'cap_net_admin,cap_net_raw+ep' ./ping + getcap ./ping | grep "cap_net_admin,cap_net_raw+ep" + if [ $? -ne 0 ]; then + echo "ERROR: set cap fail. test fail" + return 1 + fi + + attr -l ./ping | grep '"capability" has a 20 byte' + if [ $? -ne 0 ]; then + echo "ERROR: setfattr cap fail. test fail" + return 1 + fi + + echo "Yaffs2 xattr test: setcap of ping, su yaffs_test and ping again." + su yaffs_test -c "cd $yaffs_dir && ./ping 127.0.0.1 -c 3" + if [ $? -ne 0 ]; then + echo "ERROR: yaffs_test ping 127.0.0.1 fail,add cap fail, test fail" + return 1 + fi + + rm ping + echo "Yaffs2 xattr test: setcap_net_ping_test success." +} + +setfattr_net_ping_test() { + cd $yaffs_dir + if [ $? -ne 0 ]; then + echo "Error: yaffs2 dir not fount" + return 1 + fi + + cp $ping_dir ./ + chmod 755 ping + ls -al ping | grep rws + if [ $? -eq 0 ]; then + chmod -s ping + fi + + ./ping 127.0.0.1 -c 3 + if [ $? -ne 0 ]; then + echo "ERROR: ping 127.0.0.1 fail" + return 1 + fi + + # set cap_net_admin,cap_net_raw+ep of ping by setfattr, check if getcap gets the attribute correctly.; + setfattr -n security.capability -v 0sAQAAAgAwAAAAAAAAAAAAAAAAAAA= ./ping + getfattr -n security.capability ./ping | grep "security.capability=0sAQAAAgAwAAAAAAAAAAAAAAAAAAA=" + if [ $? -ne 0 ]; then + echo "ERROR: getfattr fail. test fail" + return 1 + fi + + getcap ./ping | grep "cap_net_admin,cap_net_raw+ep" + if [ $? -ne 0 ]; then + echo "ERROR: setfattr cap fail. test fail" + return 1 + fi + + rm ping + echo "Yaffs2 xattr test: setfattr_net_ping_test success." +} + +getfattr_net_ping_test() { + cd $yaffs_dir + if [ $? -ne 0 ]; then + echo "Error: yaffs2 dir not fount" + return 1 + fi + + cp $ping_dir ./ + chmod 755 ping + ls -al ping | grep rws + if [ $? -eq 0 ]; then + chmod -s ping + fi + + ./ping 127.0.0.1 -c 3 + if [ $? -ne 0 ]; then + echo "ERROR: ping 127.0.0.1 fail" + return 1 + fi + + # Set cap_net_admin,cap_net_raw+ep of ping, check if getfattr gets the attribute correctly. + setcap 'cap_net_admin,cap_net_raw+ep' ./ping + getcap ./ping | grep net_admin + if [ $? -ne 0 ]; then + echo "ERROR: set cap fail. test fail" + fi + + getfattr -n security.capability ./ping | grep "security.capability=0sAQAAAgAwAAAAAAAAAAAAAAAAAAA=" + if [ $? -ne 0 ]; then + echo "ERROR: getfattr fail. test fail" + fi + + rm ping + echo "Yaffs2 xattr test: security_xattr_ping success." +} + +pre_test || return 1 +setcap_net_ping_test || return 1 +setfattr_net_ping_test || return 1 +getfattr_net_ping_test || return 1 diff --git a/yaffs_guts.h b/yaffs_guts.h index 124e4c9..e34ca27 100644 --- a/yaffs_guts.h +++ b/yaffs_guts.h @@ -15,6 +15,7 @@ #ifndef __YAFFS_GUTS_H__ #define __YAFFS_GUTS_H__ +#include #include "yportenv.h" #define YAFFS_OK 1 @@ -956,6 +957,9 @@ int yaffs_set_xattrib(struct yaffs_obj *obj, const YCHAR *name, const void *value, int size, int flags); int yaffs_get_xattrib(struct yaffs_obj *obj, const YCHAR *name, void *value, int size); + +const struct xattr_handler *yaffs_xprefix_to_handler(const char *name); + int yaffs_list_xattrib(struct yaffs_obj *obj, char *buffer, int size); int yaffs_remove_xattrib(struct yaffs_obj *obj, const YCHAR *name); diff --git a/yaffs_nameval.c b/yaffs_nameval.c index b855365..862be08 100644 --- a/yaffs_nameval.c +++ b/yaffs_nameval.c @@ -171,7 +171,8 @@ int nval_get(struct yaffs_dev *dev, return size; if (size <= bsize) { - memcpy(buf, xb + pos, size); + if (buf) + memcpy(buf, xb + pos, size); return size; } } @@ -187,38 +188,40 @@ int nval_list(struct yaffs_dev *dev, const char *xb, int xb_size, char *buf, int s32 size; int name_len; int ncopied = 0; - int filled = 0; + const struct xattr_handler *handler; + int onecopy; memcpy(&size, xb + pos, sizeof(size)); yaffs_do_endian_s32(dev, &size); while (size > (int)(sizeof(size)) && size <= xb_size && - (pos + size) < xb_size && - !filled) { + (pos + size) < xb_size) { pos += sizeof(size); size -= sizeof(size); - name_len = strnlen((YCHAR *) (xb + pos), size); - if (ncopied + name_len + 1 < bsize) { - memcpy(buf, xb + pos, name_len * sizeof(YCHAR)); - buf += name_len; - *buf = '\0'; - buf++; - if (sizeof(YCHAR) > 1) { - *buf = '\0'; - buf++; + name_len = strnlen(xb + pos, size); + + handler = yaffs_xprefix_to_handler(xb + pos); + if (handler) { + onecopy = handler->list(handler, NULL, + buf, bsize, + xb + pos, name_len); + /* check if it is a size query */ + if (buf) { + if (onecopy + ncopied > bsize) + return -ERANGE; + buf += onecopy; } - ncopied += (name_len + 1); - } else { - filled = 1; + ncopied += onecopy; } + pos += size; if (pos < (int)(xb_size - sizeof(size))) { memcpy(&size, xb + pos, sizeof(size)); yaffs_do_endian_s32(dev, &size); - } - else + } else { size = 0; + } } return ncopied; } diff --git a/yaffs_security.c b/yaffs_security.c new file mode 100644 index 0000000..8917d4b --- /dev/null +++ b/yaffs_security.c @@ -0,0 +1,87 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. + * Description: add security xattr for yaffs2 + * Author: wanglei ,chenjie + * Create: 2019-6-12 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include "yaffs_xattr.h" +#include + +static int yaffs_init_xattrs(struct inode *inode, + const struct xattr *xattr_array, void *dentry) +{ + const struct xattr *xattr; + int err = 0; + struct yaffs_obj *obj = yaffs_security_inode_to_obj(inode); + + for (xattr = xattr_array; xattr->name != NULL; xattr++) { + err = yaffs_set_xattrib(obj, xattr->name, + xattr->value, xattr->value_len, 0); + if (err <= 0) + break; + } + return err; +} + +int yaffs_inode_init_security(struct dentry *dentry, struct inode *inode, + struct inode *dir, const struct qstr *qstr) +{ + return security_inode_init_security(inode, dir, qstr, + &yaffs_init_xattrs, dentry); +} + + +/* security xattr handler implementions */ + +static int yaffs_security_get(const struct xattr_handler *handler, + struct dentry *dentry, + const char *name, + void *buffer, size_t size) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return yaffs_getxattr(dentry, name, buffer, size); +} + +static int yaffs_security_set(const struct xattr_handler *handler, + struct dentry *dentry, const char *name, + const void *buffer, size_t size, int flags) +{ + if (strcmp(name, "") == 0) + return -EINVAL; + return yaffs_setxattr(dentry, name, buffer, size, flags); +} + +/* + * If the list is not NULL, put xattr name with prefix in list + * and return the length, otherwise just return the length + */ +static size_t yaffs_security_list(const struct xattr_handler *handler, + struct dentry *dentry, + char *list, size_t list_len, + const char *name, size_t name_len) +{ + size_t total_len = XATTR_SECURITY_PREFIX_LEN + name_len + 1; + + if (list && total_len <= list_len) { + memcpy(list, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN); + memcpy(list + XATTR_SECURITY_PREFIX_LEN, name, name_len); + list[total_len - 1] = '\0'; + } + return total_len; +} + + +const struct xattr_handler yaffs_security_xattr_handler = { + .prefix = XATTR_SECURITY_PREFIX, + .get = yaffs_security_get, + .set = yaffs_security_set, + .list = yaffs_security_list, +}; diff --git a/yaffs_vfs_multi.c b/yaffs_vfs_multi.c index 3044db7..73afa6d 100644 --- a/yaffs_vfs_multi.c +++ b/yaffs_vfs_multi.c @@ -88,6 +88,7 @@ #include #include #include +#include "yaffs_xattr.h" #if (YAFFS_NEW_FOLLOW_LINK == 1) #include @@ -952,12 +953,56 @@ static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) } #ifdef YAFFS_USE_XATTR +const struct xattr_handler *yaffs2_xattr_handlers[] = { + &yaffs_security_xattr_handler, + NULL +}; + +/* + * Check if the name xattr is supported. + * Currently, Only security xattr are supported on yaffs Now! + * Because of the restriction of yaffs2 xattr storage structure + * xattr_entry bytes = sizeof(size) + name + value + * we consider the xattr name with out dot(.) is security xattr +*/ +const struct xattr_handler *yaffs_xprefix_to_handler(const char *name) +{ + char *dot = strchr(name, '.'); + + if (!dot) + return &yaffs_security_xattr_handler; + + return NULL; +} + +struct yaffs_obj *yaffs_security_inode_to_obj(struct inode *inode) +{ + return yaffs_inode_to_obj(inode); +} + +int yaffs_init_security(struct dentry *dentry, struct inode *inode, + struct inode *dir, + struct yaffs_obj *obj, struct yaffs_dev *dev) +{ + int err = 0; + + yaffs_gross_lock(dev); + err = yaffs_inode_init_security(dentry, inode, dir, &dentry->d_name); + if (err) { + yaffs_del_obj(obj); + err = -ENOMEM; + } + yaffs_gross_unlock(dev); + + return err; +} + #if (YAFFS_NEW_XATTR > 0) -static int yaffs_setxattr(struct dentry *dentry, struct inode *inode, +int yaffs_setxattr(struct dentry *dentry, struct inode *inode, const char *name, const void *value, size_t size, int flags) { #else -static int yaffs_setxattr(struct dentry *dentry, const char *name, +int yaffs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct inode *inode = dentry->d_inode; @@ -986,11 +1031,11 @@ static int yaffs_setxattr(struct dentry *dentry, const char *name, } #if (YAFFS_NEW_XATTR > 0) -static ssize_t yaffs_getxattr(struct dentry * dentry, struct inode *inode, - const char *name, void *buff, size_t size) +ssize_t yaffs_getxattr(struct dentry *dentry, struct inode *inode, + const char *name, void *buff, size_t size) { #else -static ssize_t yaffs_getxattr(struct dentry * dentry, const char *name, +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff, size_t size) { struct inode *inode = dentry->d_inode; @@ -1042,40 +1087,38 @@ static int yaffs_removexattr(struct dentry *dentry, const char *name) return error; } -#endif -static ssize_t yaffs_listxattr(struct dentry * dentry, char *buff, size_t size) +static ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size) { struct inode *inode = dentry->d_inode; - int error = 0; + int error; struct yaffs_dev *dev; struct yaffs_obj *obj = yaffs_inode_to_obj(inode); yaffs_trace(YAFFS_TRACE_OS, "yaffs_listxattr of object %d", obj->obj_id); - if (error == 0) { - dev = obj->my_dev; - yaffs_gross_lock(dev); - error = yaffs_list_xattrib(obj, buff, size); - yaffs_gross_unlock(dev); + dev = obj->my_dev; + yaffs_gross_lock(dev); + error = yaffs_list_xattrib(obj, buff, size); + yaffs_gross_unlock(dev); - } yaffs_trace(YAFFS_TRACE_OS, "yaffs_listxattr done returning %d", error); return error; } +#endif /* YAFFS_USE_XATTR */ static const struct inode_operations yaffs_file_inode_operations = { .setattr = yaffs_setattr, #ifdef YAFFS_USE_XATTR - .setxattr = yaffs_setxattr, - .getxattr = yaffs_getxattr, - .removexattr = yaffs_removexattr, -#endif + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .removexattr = generic_removexattr, .listxattr = yaffs_listxattr, +#endif }; @@ -1200,11 +1243,11 @@ static const struct inode_operations yaffs_symlink_inode_operations = { #endif .setattr = yaffs_setattr, #ifdef YAFFS_USE_XATTR - .setxattr = yaffs_setxattr, - .getxattr = yaffs_getxattr, - .removexattr = yaffs_removexattr, -#endif + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .removexattr = generic_removexattr, .listxattr = yaffs_listxattr, +#endif }; #ifdef YAFFS_USE_OWN_IGET @@ -1407,6 +1450,15 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, if (obj) { inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); + +#ifdef YAFFS_USE_XATTR + yaffs_trace(YAFFS_TRACE_OS, "yaffs_mknod: init security"); + if (yaffs_init_security(dentry, inode, dir, obj, dev) < 0) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_mknod: init inode security failed"); + return -ENOMEM; + } +#endif d_instantiate(dentry, inode); update_dir_time(dir); yaffs_trace(YAFFS_TRACE_OS, @@ -1570,6 +1622,15 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry, struct inode *inode; inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); + +#ifdef YAFFS_USE_XATTR + yaffs_trace(YAFFS_TRACE_OS, "yaffs_symlink: init security"); + if (yaffs_init_security(dentry, inode, dir, obj, dev) < 0) { + yaffs_trace(YAFFS_TRACE_OS, + "yaffs_symlink: init inode security failed"); + return -ENOMEM; + } +#endif d_instantiate(dentry, inode); update_dir_time(dir); yaffs_trace(YAFFS_TRACE_OS, "symlink created OK"); @@ -1684,11 +1745,11 @@ static const struct inode_operations yaffs_dir_inode_operations = { .mknod = yaffs_mknod, .rename = yaffs_rename, .setattr = yaffs_setattr, - .listxattr = yaffs_listxattr, #ifdef YAFFS_USE_XATTR - .setxattr = yaffs_setxattr, - .getxattr = yaffs_getxattr, - .removexattr = yaffs_removexattr, + .setxattr = generic_setxattr, + .getxattr = generic_getxattr, + .removexattr = generic_removexattr, + .listxattr = yaffs_listxattr, #endif }; @@ -3025,6 +3086,12 @@ static struct super_block *yaffs_internal_read_super(int yaffs_version, dev->read_only = read_only; +#ifdef YAFFS_USE_XATTR + yaffs_trace(YAFFS_TRACE_ALWAYS, + "yaffs_read_super: set s_xattr handlers for security xattr."); + sb->s_xattr = yaffs2_xattr_handlers; +#endif + #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)) sb->s_fs_info = dev; #else diff --git a/yaffs_xattr.h b/yaffs_xattr.h new file mode 100644 index 0000000..40dde54 --- /dev/null +++ b/yaffs_xattr.h @@ -0,0 +1,40 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (c) Huawei Technologies Co., Ltd. 2019-2020. + * Description: head of namespace xattr + * Author: wanglei ,chenjie + * Create: 2019-6-12 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + +#ifndef __YAFFS_XATTR_H__ +#define __YAFFS_XATTR_H__ + +#include +#include +#include +#include +#include "yaffs_guts.h" + + +struct yaffs_obj *yaffs_security_inode_to_obj(struct inode *inode); + +ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, + void *buff, size_t size); + +int yaffs_setxattr(struct dentry *dentry, const char *name, + const void *value, size_t size, int flags); + +int yaffs_inode_init_security(struct dentry *dentry, struct inode *inode, + struct inode *dir, const struct qstr *qstr); + +extern const struct xattr_handler yaffs_security_xattr_handler; + +#endif /* __YAFFS_XATTR_H__ */ + -- 2.26.2.windows.1