From 1452e000d68e217e798ab51001ee15780a0a19c4 Mon Sep 17 00:00:00 2001 From: 18721213663 Date: Fri, 10 Nov 2023 16:10:24 +0800 Subject: [PATCH] faf_adapt_recent&trash Signed-off-by: 18721213663 --- fs/sharefs/authentication.c | 8 +- fs/sharefs/authentication.h | 1 + fs/sharefs/dentry.c | 2 +- fs/sharefs/inode.c | 311 ++++++++++++++++++++++++++++++++++++ fs/sharefs/lookup.c | 7 +- fs/sharefs/sharefs.h | 4 + fs/sharefs/super.c | 42 ++++- 7 files changed, 367 insertions(+), 8 deletions(-) diff --git a/fs/sharefs/authentication.c b/fs/sharefs/authentication.c index 2c79cb0a7765..f06595ab62e1 100644 --- a/fs/sharefs/authentication.c +++ b/fs/sharefs/authentication.c @@ -5,6 +5,7 @@ * Copyright (c) 2023 Huawei Device Co., Ltd. */ #include "authentication.h" +#include "sharefs.h" static inline __u16 perm_get_next_level(__u16 perm) { @@ -16,6 +17,12 @@ static inline __u16 perm_get_next_level(__u16 perm) return SHAREFS_PERM_OTHER; } +bool sharefs_check_dentry_from_pc(struct dentry *dentry) +{ + return SHAREFS_SB(dentry->d_sb)->support_pc && + SHAREFS_SB(dentry->d_sb)->support_pc == 1; +} + void fixup_perm_from_level(struct inode *dir, struct dentry *dentry) { struct sharefs_inode_info *hii = SHAREFS_I(dir); @@ -63,7 +70,6 @@ void fixup_perm_from_level(struct inode *dir, struct dentry *dentry) } break; default: - /* ! it should not get to here */ sharefs_err("sharedfs perm incorrect got default case, level:%u", level); break; } diff --git a/fs/sharefs/authentication.h b/fs/sharefs/authentication.h index 73e35a461b13..b3d7244fdf55 100644 --- a/fs/sharefs/authentication.h +++ b/fs/sharefs/authentication.h @@ -37,6 +37,7 @@ extern void sharefs_exit_configfs(void); void sharefs_root_inode_perm_init(struct inode *root_inode); void fixup_perm_from_level(struct inode *dir, struct dentry *dentry); +bool sharefs_check_dentry_from_pc(struct dentry *dentry); static inline bool is_read_only_auth(__u16 perm) { diff --git a/fs/sharefs/dentry.c b/fs/sharefs/dentry.c index dee29cace6b7..eafecfcfd1df 100644 --- a/fs/sharefs/dentry.c +++ b/fs/sharefs/dentry.c @@ -16,7 +16,7 @@ */ static int sharefs_d_revalidate(struct dentry *dentry, unsigned int flags) { - return 0; + return 1; } static void sharefs_d_release(struct dentry *dentry) diff --git a/fs/sharefs/inode.c b/fs/sharefs/inode.c index c4944f0afb88..05ea77eaae5c 100644 --- a/fs/sharefs/inode.c +++ b/fs/sharefs/inode.c @@ -9,8 +9,95 @@ * Copyright (c) 2023 Huawei Device Co., Ltd. */ +#include "authentication.h" #include "sharefs.h" +static int sharefs_create(struct inode *dir, struct dentry *dentry, + umode_t mode, bool want_excl) +{ + int err; + if (!sharefs_check_dentry_from_pc(dentry)) { + err = -EPERM; + goto out_err; + } + struct dentry *lower_dentry; + struct dentry *lower_parent_dentry = NULL; + struct path lower_path; + const struct cred *saved_cred = NULL; + __u16 child_perm; + + saved_cred = sharefs_override_file_fsids(dir, &child_perm); + if (!saved_cred) { + err = -ENOMEM; + return err; + } + + sharefs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_parent_dentry = lock_parent(lower_dentry); + err = vfs_create(d_inode(lower_parent_dentry), lower_dentry, mode, + want_excl); + if (err) + goto out; + err = sharefs_interpose(dentry, dir->i_sb, &lower_path); + if (err) + goto out; + fsstack_copy_attr_times(dir, sharefs_lower_inode(dir)); + fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry)); + +out: + unlock_dir(lower_parent_dentry); + sharefs_put_lower_path(dentry, &lower_path); + sharefs_revert_fsids(saved_cred); +out_err: + return err; +} + +static int sharefs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) +{ + int err; + if (!sharefs_check_dentry_from_pc(dentry)) { + err = -EPERM; + goto out_err; + } + struct dentry *lower_dentry; + struct dentry *lower_parent_dentry = NULL; + struct path lower_path; + const struct cred *saved_cred = NULL; + __u16 child_perm; + + saved_cred = sharefs_override_file_fsids(dir, &child_perm); + if (!saved_cred) { + err = -ENOMEM; + return err; + } + + sharefs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_parent_dentry = lock_parent(lower_dentry); + err = vfs_mkdir(d_inode(lower_parent_dentry), lower_dentry, mode); + if (err) + goto out; + + err = sharefs_interpose(dentry, dir->i_sb, &lower_path); + if (err) + goto out; + + fsstack_copy_attr_times(dir, sharefs_lower_inode(dir)); + fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry)); + /* update number of links on parent directory */ + set_nlink(dir, sharefs_lower_inode(dir)->i_nlink); + +out: + unlock_dir(lower_parent_dentry); + sharefs_put_lower_path(dentry, &lower_path); + sharefs_revert_fsids(saved_cred); + sharefs_info("after-sharefs_mkdir uid:%u, gid:%u", from_kuid(&init_user_ns, dir->i_uid), from_kgid(&init_user_ns, dir->i_gid)); + +out_err: + return err; +} + static const char *sharefs_get_link(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { @@ -99,6 +186,9 @@ sharefs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) static int sharefs_permission(struct inode *inode, int mask) { + if (SHAREFS_SB(inode->i_sb)->support_pc == 1) { + return 0; + } unsigned short mode = inode->i_mode; kuid_t cur_uid = current_fsuid(); if (uid_eq(cur_uid, ROOT_UID)) @@ -115,6 +205,220 @@ static int sharefs_permission(struct inode *inode, int mask) return -EACCES; } +static int sharefs_unlink(struct inode *dir, struct dentry *dentry) +{ + int err; + if (!sharefs_check_dentry_from_pc(dentry)) { + err = -EPERM; + goto out_err; + } + struct dentry *lower_dentry = NULL; + struct inode *lower_dir_inode = sharefs_lower_inode(dir); + struct dentry *lower_dir_dentry = NULL; + struct path lower_path; + + sharefs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + dget(lower_dentry); + lower_dir_dentry = lock_parent(lower_dentry); + err = vfs_unlink(lower_dir_inode, lower_dentry, NULL); + if (err) + goto out; + fsstack_copy_attr_times(dir, lower_dir_inode); + fsstack_copy_inode_size(dir, lower_dir_inode); + set_nlink(dentry->d_inode, + sharefs_lower_inode(dentry->d_inode)->i_nlink); + dentry->d_inode->i_ctime = dir->i_ctime; + d_drop(dentry); + +out: + unlock_dir(lower_dir_dentry); + dput(lower_dentry); + sharefs_put_lower_path(dentry, &lower_path); +out_err: + return err; +} + +static int sharefs_rmdir(struct inode *dir, struct dentry *dentry) +{ + int err; + if (!sharefs_check_dentry_from_pc(dentry)) { + err = -EPERM; + goto out_err; + } + + struct dentry *lower_dentry; + struct dentry *lower_dir_dentry; + struct path lower_path; + + sharefs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_dir_dentry = lock_parent(lower_dentry); + err = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry); + if (err) + goto out; + + d_drop(dentry); + if (dentry->d_inode) + clear_nlink(dentry->d_inode); + fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode); + fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode); + set_nlink(dir, lower_dir_dentry->d_inode->i_nlink); + +out: + unlock_dir(lower_dir_dentry); + sharefs_put_lower_path(dentry, &lower_path); +out_err: + return err; +} + +static int sharefs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry, + unsigned int flags) +{ + int err; + if (!sharefs_check_dentry_from_pc(old_dentry)) { + err = -EPERM; + goto out_err; + } + struct dentry *lower_old_dentry = NULL; + struct dentry *lower_new_dentry = NULL; + struct dentry *lower_old_dir_dentry = NULL; + struct dentry *lower_new_dir_dentry = NULL; + struct dentry *trap = NULL; + struct path lower_old_path, lower_new_path; + + if (flags) + return -EINVAL; + + sharefs_get_lower_path(old_dentry, &lower_old_path); + sharefs_get_lower_path(new_dentry, &lower_new_path); + lower_old_dentry = lower_old_path.dentry; + lower_new_dentry = lower_new_path.dentry; + lower_old_dir_dentry = dget_parent(lower_old_dentry); + lower_new_dir_dentry = dget_parent(lower_new_dentry); + trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + /* source should not be ancestor of target */ + if (trap == lower_old_dentry) { + err = -EINVAL; + goto out; + } + /* target should not be ancestor of source */ + if (trap == lower_new_dentry) { + err = -ENOTEMPTY; + goto out; + } + + err = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry, + lower_new_dir_dentry->d_inode, lower_new_dentry, + NULL, 0); + if (err) + goto out; + + fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode); + fsstack_copy_inode_size(new_dir, lower_new_dir_dentry->d_inode); + if (new_dir != old_dir) { + fsstack_copy_attr_all(old_dir, + lower_old_dir_dentry->d_inode); + fsstack_copy_inode_size(old_dir, + lower_old_dir_dentry->d_inode); + } + +out: + unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry); + dput(lower_old_dir_dentry); + dput(lower_new_dir_dentry); + sharefs_put_lower_path(old_dentry, &lower_old_path); + sharefs_put_lower_path(new_dentry, &lower_new_path); +out_err: + return err; +} + +static int sharefs_setattr(struct dentry *dentry, struct iattr *ia) +{ + int err; + if (!sharefs_check_dentry_from_pc(dentry)) { + err = -EPERM; + goto out_err; + } + + struct dentry *lower_dentry; + struct inode *inode; + struct inode *lower_inode; + struct path lower_path; + struct iattr lower_ia; + + inode = dentry->d_inode; + /* + * Check if user has permission to change inode. We don't check if + * this user can change the lower inode: that should happen when + * calling notify_change on the lower inode. + */ + + err = setattr_prepare(dentry, ia); + if (err) + goto out_err; + + sharefs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_inode = sharefs_lower_inode(inode); + + /* prepare our own lower struct iattr (with the lower file) */ + memcpy(&lower_ia, ia, sizeof(lower_ia)); + if (ia->ia_valid & ATTR_FILE) + lower_ia.ia_file = sharefs_lower_file(ia->ia_file); + + /* + * If shrinking, first truncate upper level to cancel writing dirty + * pages beyond the new eof; and also if its' maxbytes is more + * limiting (fail with -EFBIG before making any change to the lower + * level). There is no need to vmtruncate the upper level + * afterwards in the other cases: we fsstack_copy_inode_size from + * the lower level. + */ + if (ia->ia_valid & ATTR_SIZE) { + err = inode_newsize_ok(inode, ia->ia_size); + if (err) + goto out; + truncate_setsize(inode, ia->ia_size); + } + + /* + * mode change is for clearing setuid/setgid bits. Allow lower fs + * to interpret this in its own way. + */ + if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID)) + lower_ia.ia_valid &= ~ATTR_MODE; + + /* notify the (possibly copied-up) lower inode */ + /* + * Note: we use lower_dentry->d_inode, because lower_inode may be + * unlinked (no inode->i_sb and i_ino==0. This happens if someone + * tries to open(), unlink(), then ftruncate() a file. + */ + + inode_lock(d_inode(lower_dentry)); + err = notify_change(lower_dentry, &lower_ia, /* note: lower_ia */ + NULL); + inode_unlock(d_inode(lower_dentry)); + + if (err) + goto out; + + /* get attributes from the lower inode */ + fsstack_copy_attr_all(inode, lower_inode); + /* + * Not running fsstack_copy_inode_size(inode, lower_inode), because + * VFS should update our inode size, and notify_change on + * lower_inode should update its size. + */ + +out: + sharefs_put_lower_path(dentry, &lower_path); +out_err: + return err; +} + const struct inode_operations sharefs_symlink_iops = { .permission = sharefs_permission, .getattr = sharefs_getattr, @@ -127,10 +431,17 @@ const struct inode_operations sharefs_dir_iops = { .permission = sharefs_permission, .getattr = sharefs_getattr, .listxattr = sharefs_listxattr, + .unlink = sharefs_unlink, + .rmdir = sharefs_rmdir, + .rename = sharefs_rename, + .create = sharefs_create, + .mkdir = sharefs_mkdir, + .setattr = sharefs_setattr, }; const struct inode_operations sharefs_main_iops = { .permission = sharefs_permission, .getattr = sharefs_getattr, .listxattr = sharefs_listxattr, + .setattr = sharefs_setattr, }; diff --git a/fs/sharefs/lookup.c b/fs/sharefs/lookup.c index 315900c03fd2..c56814d50cdd 100644 --- a/fs/sharefs/lookup.c +++ b/fs/sharefs/lookup.c @@ -9,8 +9,8 @@ * Copyright (c) 2023 Huawei Device Co., Ltd. */ -#include "sharefs.h" #include "authentication.h" +#include "sharefs.h" /* The dentry cache is just so we have properly sized dentries */ static struct kmem_cache *sharefs_dentry_cachep; @@ -237,7 +237,6 @@ static struct dentry *__sharefs_lookup(struct dentry *dentry, } goto out; } - /* * We don't consider ENOENT an error, and we want to return a * negative dentry. @@ -317,7 +316,9 @@ struct dentry *sharefs_lookup(struct inode *dir, struct dentry *dentry, /* update parent directory's atime */ fsstack_copy_attr_atime(d_inode(parent), sharefs_lower_inode(d_inode(parent))); - fixup_perm_from_level(d_inode(parent), dentry); + if (!sharefs_check_dentry_from_pc(dentry)) + fixup_perm_from_level(d_inode(parent), dentry); + out: sharefs_put_lower_path(parent, &lower_parent_path); dput(parent); diff --git a/fs/sharefs/sharefs.h b/fs/sharefs/sharefs.h index 143f047b235f..5898e1433ee4 100644 --- a/fs/sharefs/sharefs.h +++ b/fs/sharefs/sharefs.h @@ -63,6 +63,7 @@ struct sharefs_sb_info { struct super_block *lower_sb; /* multi user */ unsigned int user_id; + unsigned int support_pc; }; /* operations vectors defined in specific files */ @@ -91,6 +92,9 @@ extern int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, struct path *path); extern int sharefs_parse_options(struct sharefs_sb_info *sbi, const char *data); +extern const struct cred *sharefs_override_file_fsids(struct inode *dir, + __u16 *_perm); +extern void sharefs_revert_fsids(const struct cred *old_cred); /* * inode to private data diff --git a/fs/sharefs/super.c b/fs/sharefs/super.c index bbe65944647f..36455c98bab8 100644 --- a/fs/sharefs/super.c +++ b/fs/sharefs/super.c @@ -13,12 +13,14 @@ enum { OPT_USER_ID, - OPT_ERR, + OP_ENABLE, + OPT_ERR, }; static match_table_t sharefs_tokens = { { OPT_USER_ID, "user_id=%s" }, - { OPT_ERR, NULL } + { OP_ENABLE, "support_pc=%s" }, + { OPT_ERR, NULL } }; int sharefs_parse_options(struct sharefs_sb_info *sbi, const char *data) @@ -29,6 +31,7 @@ int sharefs_parse_options(struct sharefs_sb_info *sbi, const char *data) char *options_src = NULL; substring_t args[MAX_OPT_ARGS]; unsigned int user_id = 0; + unsigned int support_pc = 0; int err = 0; options = kstrdup(data, GFP_KERNEL); @@ -58,7 +61,18 @@ int sharefs_parse_options(struct sharefs_sb_info *sbi, const char *data) sbi->user_id = user_id; } break; - default: + case OP_ENABLE: + name = match_strdup(&args[0]); + if (name) { + err = kstrtouint(name, 10, &support_pc); + kfree(name); + name = NULL; + if (err) + goto out; + sbi->support_pc = support_pc; + } + break; + default: err = -EINVAL; goto out; } @@ -195,6 +209,28 @@ void sharefs_destroy_inode_cache(void) kmem_cache_destroy(sharefs_inode_cachep); } +const struct cred *sharefs_override_file_fsids(struct inode *dir, __u16 *_perm) +{ + struct cred *cred = NULL; + const struct cred *old_cred = NULL; + cred = prepare_creds(); + if (!cred) + return NULL; + + cred->fsuid = dir->i_uid; + cred->fsgid = dir->i_gid; + old_cred = override_creds(cred); + return old_cred; +} + +void sharefs_revert_fsids(const struct cred *old_cred) +{ + const struct cred *cur_cred; + cur_cred = current->cred; + revert_creds(old_cred); + put_cred(cur_cred); +} + const struct super_operations sharefs_sops = { .put_super = sharefs_put_super, .statfs = sharefs_statfs, -- Gitee