From: liaohua <
liaohua4@huawei.com>
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 <liaohua4@huawei.com>
---
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 <linux/xattr.h>
#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 <leisure.wang@huawei.com>,chenjie <chenjie6@huawei.com>
+ * 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 <linux/errno.h>
+
+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 <linux/interrupt.h>
#include <linux/string.h>
#include <linux/ctype.h>
+#include "yaffs_xattr.h"
#if (YAFFS_NEW_FOLLOW_LINK == 1)
#include <linux/namei.h>
@@ -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 <leisure.wang@huawei.com>,chenjie <chenjie6@huawei.com>
+ * 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 <linux/fs.h>
+#include <linux/xattr.h>
+#include <linux/mtd/mtd.h>
+#include <linux/security.h>
+#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