Whamcloud - gitweb
LU-12826 mdt: limit root to change project state by default 44/36544/10
authorWang Shilong <wshilong@ddn.com>
Tue, 22 Oct 2019 06:15:02 +0000 (14:15 +0800)
committerOleg Drokin <green@whamcloud.com>
Sat, 14 Dec 2019 05:56:59 +0000 (05:56 +0000)
The current project quota implementation allows users to
change the Project ID of files for which they have write
permission to any value. This is not useful if the project
quota is intended to be enforced instead of only being used
for quota accouting.

Change it so that by default only root can change the projid
of a file. Setting "mdt.*.enable_chprojid_gid" will allow
users with the specified numeric Group ID (eg. 1 = "admin") to
also change the projid of a file. Use "-1" to return the previous
behavior where all users can change the projid of their files.

Change-Id: I91c138d29f4d0b9bc607528d86893451904c9892
Signed-off-by: Wang Shilong <wshilong@ddn.com>
Reviewed-on: https://review.whamcloud.com/36544
Tested-by: jenkins <devops@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Li Xi <lixi@ddn.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Stephan Thiell <sthiell@stanford.edu>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/include/md_object.h
lustre/mdd/mdd_object.c
lustre/mdt/mdt_handler.c
lustre/mdt/mdt_internal.h
lustre/mdt/mdt_lproc.c
lustre/mdt/mdt_reint.c
lustre/tests/sanity-quota.sh

index 6375e0b..cb0bf71 100644 (file)
@@ -137,6 +137,7 @@ struct md_attr {
        int                      ma_lmv_size;
        int                      ma_default_lmv_size;
        int                      ma_acl_size;
+       int                      ma_enable_chprojid_gid;
 };
 
 /** Additional parameters for create */
index aef4421..6df8870 100644 (file)
@@ -632,6 +632,22 @@ int mdd_update_time(const struct lu_env *env, struct mdd_object *obj,
        RETURN(rc);
 }
 
+
+static bool is_project_state_change(const struct lu_attr *oattr,
+                                   struct lu_attr *la)
+{
+       if (la->la_valid & LA_PROJID &&
+           oattr->la_projid != la->la_projid)
+               return true;
+
+       if ((la->la_valid & LA_FLAGS) &&
+           (la->la_flags & LUSTRE_PROJINHERIT_FL) !=
+           (oattr->la_flags & LUSTRE_PROJINHERIT_FL))
+               return true;
+
+       return false;
+}
+
 /*
  * This gives the same functionality as the code between
  * sys_chmod and inode_setattr
@@ -641,10 +657,12 @@ int mdd_update_time(const struct lu_env *env, struct mdd_object *obj,
  */
 static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj,
                        const struct lu_attr *oattr, struct lu_attr *la,
-                       const unsigned long flags)
+                       const struct md_attr *ma)
 {
        struct lu_ucred  *uc;
        int               rc = 0;
+       const unsigned long flags = ma->ma_attr_flags;
+
        ENTRY;
 
        if (!la->la_valid)
@@ -664,6 +682,14 @@ static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj,
        if (uc == NULL)
                RETURN(0);
 
+       if (is_project_state_change(oattr, la)) {
+               if (!md_capable(uc, CFS_CAP_SYS_RESOURCE) &&
+                   !lustre_in_group_p(uc, ma->ma_enable_chprojid_gid) &&
+                   !(ma->ma_enable_chprojid_gid == -1 &&
+                     mdd_permission_internal(env, obj, oattr, MAY_WRITE)))
+                       RETURN(-EPERM);
+       }
+
        if (la->la_valid == LA_CTIME) {
                if (!(flags & MDS_PERM_BYPASS))
                        /* This is only for set ctime when rename's source is
@@ -1186,7 +1212,7 @@ int mdd_attr_set(const struct lu_env *env, struct md_object *obj,
                RETURN(rc);
 
        *la_copy = ma->ma_attr;
-       rc = mdd_fix_attr(env, mdd_obj, attr, la_copy, ma->ma_attr_flags);
+       rc = mdd_fix_attr(env, mdd_obj, attr, la_copy, ma);
        if (rc)
                RETURN(rc);
 
index 84e21d6..50191b3 100644 (file)
@@ -5430,6 +5430,7 @@ static int mdt_init0(const struct lu_env *env, struct mdt_device *m,
        m->mdt_enable_striped_dir = 1;
        m->mdt_enable_dir_migration = 1;
        m->mdt_enable_remote_dir_gid = 0;
+       m->mdt_enable_chprojid_gid = 0;
        m->mdt_enable_remote_rename = 1;
 
        atomic_set(&m->mdt_mds_mds_conns, 0);
index 2973f75..1e1d6da 100644 (file)
@@ -262,6 +262,8 @@ struct mdt_device {
                                   /* user with gid can create remote/striped
                                    * dir, and set default dir stripe */
        gid_t                      mdt_enable_remote_dir_gid;
+                                  /* user with this gid can change projid */
+       gid_t                      mdt_enable_chprojid_gid;
 
        /* lock for osfs and md_root */
        spinlock_t                 mdt_lock;
index 1ad735e..a3adf18 100644 (file)
@@ -649,6 +649,36 @@ static ssize_t enable_remote_dir_gid_store(struct kobject *kobj,
 }
 LUSTRE_RW_ATTR(enable_remote_dir_gid);
 
+static ssize_t enable_chprojid_gid_show(struct kobject *kobj,
+                                       struct attribute *attr, char *buf)
+{
+       struct obd_device *obd = container_of(kobj, struct obd_device,
+                                             obd_kset.kobj);
+       struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                        (int)mdt->mdt_enable_chprojid_gid);
+}
+
+static ssize_t enable_chprojid_gid_store(struct kobject *kobj,
+                                        struct attribute *attr,
+                                        const char *buffer, size_t count)
+{
+       struct obd_device *obd = container_of(kobj, struct obd_device,
+                                             obd_kset.kobj);
+       struct mdt_device *mdt = mdt_dev(obd->obd_lu_dev);
+       int val;
+       int rc;
+
+       rc = kstrtoint(buffer, 0, &val);
+       if (rc)
+               return rc;
+
+       mdt->mdt_enable_chprojid_gid = val;
+       return count;
+}
+LUSTRE_RW_ATTR(enable_chprojid_gid);
+
 static ssize_t enable_striped_dir_show(struct kobject *kobj,
                                       struct attribute *attr, char *buf)
 {
@@ -1050,6 +1080,7 @@ static struct attribute *mdt_attrs[] = {
        &lustre_attr_evict_tgt_nids.attr,
        &lustre_attr_enable_remote_dir.attr,
        &lustre_attr_enable_remote_dir_gid.attr,
+       &lustre_attr_enable_chprojid_gid.attr,
        &lustre_attr_enable_striped_dir.attr,
        &lustre_attr_enable_dir_migration.attr,
        &lustre_attr_enable_remote_rename.attr,
index 81c148f..18323ce 100644 (file)
@@ -662,6 +662,7 @@ static int mdt_reint_setattr(struct mdt_thread_info *info,
        if (mdt_object_remote(mo))
                GOTO(out_put, rc = -EREMOTE);
 
+       ma->ma_enable_chprojid_gid = mdt->mdt_enable_chprojid_gid;
        /* revoke lease lock if size is going to be changed */
        if (unlikely(ma->ma_attr.la_valid & LA_SIZE &&
                     !(ma->ma_attr_flags & MDS_TRUNC_KEEP_LEASE) &&
index 23a1ae8..b091929 100755 (executable)
@@ -3481,6 +3481,50 @@ test_65() {
 }
 run_test 65 "Check lfs quota result"
 
+test_66() {
+       ! is_project_quota_supported &&
+               skip "Project quota is not supported"
+       setup_quota_test || error "setup quota failed with $?"
+       stack_trap cleanup_quota_test EXIT
+       local old=$(do_facet mds1 $LCTL get_param -n \
+                   mdt.*.enable_chprojid_gid | head -1)
+       local testdir=$DIR/$tdir/foo
+
+       do_facet mds1 $LCTL set_param mdt.*.enable_chprojid_gid=0
+       stack_trap "do_facet mds1 $LCTL set_param mdt.*.enable_chprojid_gid=0" \
+               EXIT
+
+       test_mkdir -i 0 -c 1 $testdir || error "failed to mkdir"
+       chown -R $TSTID:$TSTID $testdir
+       change_project -sp $TSTPRJID $testdir
+       $RUNAS mkdir $testdir/foo || error "failed to mkdir foo"
+
+       $RUNAS lfs project -p 0 $testdir/foo &&
+               error "nonroot user should fail to set projid"
+
+       $RUNAS lfs project -C $testdir/foo &&
+               error "nonroot user should fail to clear projid"
+
+       change_project -C $testdir/foo || error "failed to clear project"
+
+       do_facet mds1 $LCTL set_param mdt.*.enable_chprojid_gid=-1
+       $RUNAS lfs project -p $TSTPRJID $testdir/foo || error \
+       "failed to set projid with normal user when enable_chprojid_gid=-1"
+
+       $RUNAS lfs project -rC $testdir/ || error \
+"failed to clear project state with normal user when enable_chprojid_gid=-1"
+
+       touch $testdir/bar || error "failed touch $testdir/bar"
+       $RUNAS lfs project -p $TSTPRJID $testdir/bar && error \
+       "normal user should not be able to set projid on root owned file"
+
+       change_project -p $TSTPRJID $testdir/bar || error \
+               "root should be able to change its own file's projid"
+
+       cleanup_quota_test
+}
+run_test 66 "nonroot user can not change project state in default"
+
 quota_fini()
 {
        do_nodes $(comma_list $(nodes_list)) "lctl set_param debug=-quota"