Whamcloud - gitweb
LU-18109 nodemap: fix idmap offset for root 56/57856/6
authorSebastien Buisson <sbuisson@ddn.com>
Wed, 22 Jan 2025 14:20:11 +0000 (15:20 +0100)
committerOleg Drokin <green@whamcloud.com>
Sat, 22 Feb 2025 23:42:04 +0000 (23:42 +0000)
root must be mapped and offset just like other ids, so that all ids on
the client in the range [0, offset_limit-1] are mapped to the
filesystem id range [offset, offset+offset_limit-1].
This means that as soon as an offset is defined on a nodemap, root is
necessarily mapped:
- if admin=1, root id is offset
- if admin=0, root is squashed then offset.
Similarly:
- if trusted=1, ids are mapped (with any explicit mapping) and offset
- if trusted=0, ids are squashed then offset.

Moreover, add_offset and del_offset operations are only allowed on the
MGS or for a dynamic nodemap.

Finally, enhance sanity-sec test_27ab to test id mappings with offset.

Fixes: e3051ad0f1 ("LU-18109 utils: adding nodemap offset capability")
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I7a20c59496174d9d1fc040c5b3b43d8dad3447f9
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/57856
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Marc Vef <mvef@whamcloud.com>
lustre/mdt/mdt_lib.c
lustre/ptlrpc/nodemap_handler.c
lustre/tests/sanity-sec.sh

index 943d23d..d4cb5a9 100644 (file)
@@ -258,7 +258,10 @@ static int new_init_ucred(struct mdt_thread_info *info, ucred_init_type_t type,
                GOTO(out_nodemap, rc = -EACCES);
        }
 
-       if (nodemap && ucred->uc_o_uid == nodemap->nm_squash_uid &&
+       if (nodemap &&
+           ucred->uc_o_uid == nodemap_map_id(nodemap, NODEMAP_UID,
+                                             NODEMAP_CLIENT_TO_FS,
+                                             nodemap->nm_squash_uid) &&
            nodemap->nmf_deny_unknown)
                /* deny access before we get identity ref */
                GOTO(out, rc = -EACCES);
@@ -528,8 +531,11 @@ static int old_init_ucred_common(struct mdt_thread_info *info,
        struct mdt_device *mdt = info->mti_mdt;
        struct md_identity *identity = NULL;
 
-       if (nodemap && uc->uc_o_uid == nodemap->nm_squash_uid
-           && nodemap->nmf_deny_unknown)
+       if (nodemap &&
+           uc->uc_o_uid == nodemap_map_id(nodemap, NODEMAP_UID,
+                                          NODEMAP_CLIENT_TO_FS,
+                                          nodemap->nm_squash_uid) &&
+           nodemap->nmf_deny_unknown)
                /* deny access before we get identity ref */
                RETURN(-EACCES);
 
index 5c04e3d..cdd5572 100644 (file)
@@ -780,9 +780,12 @@ __u32 nodemap_map_id(struct lu_nodemap *nodemap,
        if (unlikely(nodemap == NULL))
                goto out;
 
-       if (id == 0) {
+       if (id_type != NODEMAP_PROJID && id == 0) {
+               /* root id is mapped and offset just as the other ids. This
+                * means root cannot remain root as soon as offset is defined.
+                */
                if (nodemap->nmf_allow_root_access)
-                       goto out;
+                       goto offset;
                goto map;
        }
 
@@ -847,13 +850,30 @@ offset:
                GOTO(out, found_id);
 
        if (tree_type == NODEMAP_FS_TO_CLIENT) {
+               if (found_id < offset_start) {
+                       /* If we are outside boundaries, try to squash before
+                        * offsetting, and return unmapped otherwise.
+                        */
+                       if (!attempted_squash)
+                               GOTO(squash, found_id);
+
+                       CDEBUG(D_SEC,
+                              "%s: squash_id for type %u is below nodemap start %u, use unmapped value %u\n",
+                              nodemap->nm_name, id_type, offset_start,
+                              found_id);
+                       GOTO(out, found_id);
+               }
                found_id -= offset_start;
        } else {
-               if (found_id >= offset_limit && !attempted_squash)
-                       GOTO(squash, found_id);
-
-               if (attempted_squash) {
-                       CERROR("%s: squash_id for type %u is outside nodemap limit %u, use unmapped value %u\n",
+               if (found_id >= offset_limit) {
+                       /* If we are outside boundaries, try to squash before
+                        * offsetting, and return unmapped otherwise.
+                        */
+                       if (!attempted_squash)
+                               GOTO(squash, found_id);
+
+                       CDEBUG(D_SEC,
+                              "%s: squash_id for type %u is outside nodemap limit %u, use unmapped value %u\n",
                               nodemap->nm_name, id_type, offset_limit,
                               found_id);
                        GOTO(out, found_id);
@@ -1681,7 +1701,8 @@ EXPORT_SYMBOL(nodemap_set_squash_projid);
  * Check if nodemap allows setting quota.
  *
  * If nodemap is not active, always allow.
- * For user and group quota, allow if the nodemap allows root access.
+ * For user and group quota, allow if the nodemap allows root access, unless
+ * root is mapped.
  * For project quota, allow if project id is not squashed or deny_unknown
  * is not set.
  *
@@ -1699,6 +1720,9 @@ bool nodemap_can_setquota(struct lu_nodemap *nodemap, __u32 qc_type, __u32 id)
            !(nodemap->nmf_rbac & NODEMAP_RBAC_QUOTA_OPS))
                return false;
 
+       if (nodemap_map_id(nodemap, NODEMAP_UID, NODEMAP_CLIENT_TO_FS, 0) != 0)
+               return false;
+
        if (qc_type == PRJQUOTA) {
                id = nodemap_map_id(nodemap, NODEMAP_PROJID,
                                    NODEMAP_CLIENT_TO_FS, id);
@@ -2011,6 +2035,8 @@ int nodemap_add_offset(const char *nodemap_name, char *offset)
 
        if (is_default_nodemap(nodemap))
                GOTO(out_putref, rc = -EINVAL);
+       if (!allow_op_on_nm(nodemap))
+               GOTO(out_putref, rc = -EPERM);
 
        if (nodemap->nm_offset_start_uid) {
                /* nodemap has already offset  */
@@ -2099,6 +2125,8 @@ int nodemap_del_offset(const char *nodemap_name)
 
        if (is_default_nodemap(nodemap))
                GOTO(out_putref, rc = -EINVAL);
+       if (!allow_op_on_nm(nodemap))
+               GOTO(out_putref, rc = -EPERM);
 
        rc = nodemap_del_offset_helper(nodemap);
        if (rc == 0)
index ad6aa82..536e628 100755 (executable)
@@ -2360,35 +2360,44 @@ test_27aa() { #LU-17922
 run_test 27aa "test nodemap idmap range"
 
 test_27ab() { #LU-18109
-       local idmap
+       local offset_start=100000
+       local offset_limit=200000
+       local nid=1.1.1.1@tcp777
+       local activedefault
+       local nm1=Test18109
+       local nm2=OffsetTest
+       local squash=65534
+       local id_start=500
+       local expected
        local id=500
+       local idmap
        local offset
 
        (( MDS1_VERSION > $(version_code 2.16.50.170) )) ||
                skip "need MDS > 2.16.50.170 for nodemap range offset"
 
-       do_facet mgs $LCTL nodemap_add Test18109 ||
-               error "unable to add Test18109 as nodemap"
-       stack_trap "do_facet mgs $LCTL nodemap_del Test18109 || true"
+       do_facet mgs $LCTL nodemap_add $nm1 ||
+               error "unable to add $nm1 as nodemap"
+       stack_trap "do_facet mgs $LCTL nodemap_del $nm1 || true"
 
-       do_facet mgs $LCTL nodemap_add OffsetTest ||
-               error "unable to add OffsetTest as nodemap"
-       stack_trap "do_facet mgs $LCTL nodemap_del OffsetTest || true"
+       do_facet mgs $LCTL nodemap_add $nm2 ||
+               error "unable to add $nm2 as nodemap"
+       stack_trap "do_facet mgs $LCTL nodemap_del $nm2 || true"
 
-       do_facet mgs $LCTL nodemap_add_offset --name Test18109 \
-               --offset 100000 --limit 200000 ||
-                       error "cannot set offset 100000-299999 for Test18109"
+       do_facet mgs $LCTL nodemap_add_offset --name $nm1 \
+               --offset $offset_start --limit $offset_limit ||
+                       error "cannot set offset $offset_start-$((offset_start+offset_limit-1)) for $nm1"
 
        #expected error, invalid offset range supplied
-       do_facet mgs $LCTL nodemap_add_offset --name OffsetTest \
-               --offset 150000 --limit 100000 &&
-                       error "cannot set offset 150000-249999 for OffsetTest"
+       do_facet mgs $LCTL nodemap_add_offset --name $nm2 \
+               --offset $((offset_start+50000)) --limit 100000 &&
+                       error "setting offset $((offset_start+50000))-249999 on $nm2 should fail"
 
-       do_facet mgs $LCTL nodemap_add_idmap --name Test18109 \
+       do_facet mgs $LCTL nodemap_add_idmap --name $nm1 \
                 --idtype uid --idmap 500-509:0-9 ||
                 error "unable to add idmap range 500-509:0-9"
 
-       idmap=$(do_facet mgs $LCTL get_param nodemap.Test18109.idmap |
+       idmap=$(do_facet mgs $LCTL get_param nodemap.$nm1.idmap |
                grep idtype)
        while IFS= read -r idmap; do
                if (( $id <= 509 )); then
@@ -2398,51 +2407,194 @@ test_27ab() { #LU-18109
                ((id++))
        done < <(echo "$idmap")
 
-       do_facet mgs $LCTL nodemap_del_idmap --name Test18109 \
+       do_facet mgs $LCTL nodemap_add_range --name $nm1 --range $nid ||
+               error "Add range $nid to $nm1 failed"
+       do_facet mgs $LCTL nodemap_modify --name $nm1 \
+               --property admin --value 1 ||
+               error "Setting admin=1 on $nm1 failed"
+       do_facet mgs $LCTL nodemap_modify --name $nm1 \
+               --property trusted --value 1 ||
+               error "Setting trusted=1 on $nm1 failed"
+       do_facet mgs $LCTL nodemap_modify --name $nm1 \
+               --property squash_uid --value $squash ||
+               error "Setting squash_uid=$squash on $nm1 failed"
+       do_facet mgs $LCTL nodemap_modify --name $nm1 \
+               --property squash_gid --value $squash ||
+               error "Setting squash_gid=$squash on $nm1 failed"
+
+       activedefault=$(do_facet mgs $LCTL get_param -n nodemap.active)
+       if ((activedefault != 1)); then
+               do_facet mgs $LCTL nodemap_activate 1
+               wait_nm_sync active
+               stack_trap cleanup_active EXIT
+       fi
+
+       if (( MDS1_VERSION >= $(version_code 2.16.51.45) )); then
+               # with admin=1, we expect root to be offset
+               id=0
+               expected=$offset_start
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype uid --id $id)
+               ((idmap == expected)) ||
+                       error "uid $id should be mapped to $expected"
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype gid --id $id)
+               ((idmap == expected)) ||
+                       error "gid $id should be mapped to $expected"
+               # with trusted=1, we expect ids to be offset
+               id=$((id_start+1))
+               expected=$((offset_start+id_start+1))
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype uid --id $id)
+               ((idmap == expected)) ||
+                       error "uid $id should be mapped to $expected"
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype gid --id $id)
+               ((idmap == expected)) ||
+                       error "gid $id should be mapped to $expected"
+
+               do_facet mgs $LCTL nodemap_modify --name $nm1 \
+                       --property trusted --value 0 ||
+                       error "Setting trusted=0 on $nm1 failed"
+
+               # with trusted=0, we expect uid to be mapped+offset,
+               # gid to be squashed+offset
+               expected=$((offset_start+1))
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype uid --id $id)
+               ((idmap == expected)) ||
+                       error "uid $id should be mapped to $expected"
+               expected=$((offset_start+squash))
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype gid --id $id)
+               ((idmap == expected)) ||
+                       error "gid $id should be mapped to $expected"
+
+               do_facet mgs $LCTL nodemap_modify --name $nm1 \
+                       --property admin --value 0 ||
+                       error "Setting admin=0 on $nm1 failed"
+
+               # with admin=0, we expect root to be squashed+offset
+               id=0
+               expected=$((offset_start+squash))
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype uid --id $id)
+               ((idmap == expected)) ||
+                       error "uid $id should be mapped to $expected"
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype gid --id $id)
+               ((idmap == expected)) ||
+                       error "gid $id should be mapped to $expected"
+
+               do_facet mgs $LCTL nodemap_modify --name $nm1 \
+                       --property admin --value 1 ||
+                       error "Setting admin=1 on $nm1 failed"
+               do_facet mgs $LCTL nodemap_modify --name $nm1 \
+                       --property trusted --value 1 ||
+                       error "Setting trusted=1 on $nm1 failed"
+       fi
+
+       do_facet mgs $LCTL nodemap_del_idmap --name $nm1 \
                 --idtype uid --idmap 500-509:0 ||
                        error "cannot delete idmap range 500-509:0"
 
        #expected error, invalid secondary range supplied
-       do_facet mgs $LCTL nodemap_add --name Test18109 \
+       do_facet mgs $LCTL nodemap_add --name $nm1 \
                 --idtype uid --idmap 500-509:200000-200010 &&
                 error "Invalid range 200000-200010 was supplied"
 
-       (( $(do_facet mgs $LCTL get_param nodemap.Test18109.idmap |
+       (( $(do_facet mgs $LCTL get_param nodemap.$nm1.idmap |
                grep -c idtype) == 0 )) ||
                error "invalid range 200000-200010 supplied and passed"
 
-       offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset |
+       offset=$(do_facet mgs $LCTL get_param nodemap.$nm1.offset |
                 grep start_uid)
-       [[ "$offset" == *"start_uid: 100000"* ]] ||
-               error "expected start_uid of 100000 not found before remounting"
+       [[ "$offset" == *"start_uid: $offset_start"* ]] ||
+               error "expected start_uid of $offset_start not found before remounting"
 
-       offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset |
+       offset=$(do_facet mgs $LCTL get_param nodemap.$nm1.offset |
                 grep limit_uid)
-       [[ "$offset" == *"limit_uid: 200000"* ]] ||
-               error "expected limit_uid of 200000 not found before remounting"
+       [[ "$offset" == *"limit_uid: $offset_limit"* ]] ||
+               error "expected limit_uid of $offset_limit not found before remounting"
+
+       if (( MDS1_VERSION >= $(version_code 2.16.51.45) )); then
+               # with admin=1, we expect root to be offset
+               id=0
+               expected=$offset_start
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype uid --id $id)
+               ((idmap == expected)) ||
+                       error "uid $id should be mapped to $expected"
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype gid --id $id)
+               ((idmap == expected)) ||
+                       error "gid $id should be mapped to $expected"
+               # with trusted=1, we expect ids to be offset
+               id=$((id_start+1))
+               expected=$((offset_start+id_start+1))
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype uid --id $id)
+               ((idmap == expected)) ||
+                       error "uid $id should be mapped to $expected"
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype gid --id $id)
+               ((idmap == expected)) ||
+                       error "gid $id should be mapped to $expected"
+
+               do_facet mgs $LCTL nodemap_modify --name $nm1 \
+                       --property trusted --value 0 ||
+                       error "Setting trusted=0 on $nm1 failed"
+
+               # with trusted=0, we expect uid to be squashed+offset
+               expected=$((offset_start+squash))
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype uid --id $id)
+               ((idmap == expected)) ||
+                       error "uid $id should be mapped to $expected"
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype gid --id $id)
+               ((idmap == expected)) ||
+                       error "gid $id should be mapped to $expected"
+
+               do_facet mgs $LCTL nodemap_modify --name $nm1 \
+                       --property admin --value 0 ||
+                       error "Setting admin=0 on $nm1 failed"
+
+               # with admin=0, we expect root to be squashed+offset
+               id=0
+               expected=$((offset_start+squash))
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype uid --id $id)
+               ((idmap == expected)) ||
+                       error "uid $id should be mapped to $expected"
+               idmap=$(do_facet mgs $LCTL nodemap_test_id --nid $nid \
+                       --idtype gid --id $id)
+               ((idmap == expected)) ||
+                       error "gid $id should be mapped to $expected"
+       fi
 
        stopall || error "failed to unmount servers"
        setupall || error "failed to remount servers"
 
-       offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset |
+       offset=$(do_facet mgs $LCTL get_param nodemap.$nm1.offset |
                 grep start_uid)
-       [[ "$offset" == *"start_uid: 100000"* ]] ||
-               error "expected start_uid of 100000 not found after remounting"
+       [[ "$offset" == *"start_uid: $offset_start"* ]] ||
+               error "expected start_uid of $offset_start not found after remounting"
 
-       offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset |
+       offset=$(do_facet mgs $LCTL get_param nodemap.$nm1.offset |
                 grep limit_uid)
-       [[ "$offset" == *"limit_uid: 200000"* ]] ||
-               error "expected limit_uid of 200000 not found after remounting"
+       [[ "$offset" == *"limit_uid: $offset_limit"* ]] ||
+               error "expected limit_uid of $offset_limit not found after remounting"
 
-       do_facet mgs $LCTL nodemap_del_offset --name Test18109 ||
-               error "cannot del offset from Test18109"
+       do_facet mgs $LCTL nodemap_del_offset --name $nm1 ||
+               error "cannot del offset from $nm1"
 
-       offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset |
+       offset=$(do_facet mgs $LCTL get_param nodemap.$nm1.offset |
                 grep start_uid)
        [[ "$offset" == *"start_uid: 0"* ]] ||
                error "expected start_uid 0, found $offset"
 
-       offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset |
+       offset=$(do_facet mgs $LCTL get_param nodemap.$nm1.offset |
                 grep limit_uid)
        [[ "$offset" == *"limit_uid: 0"* ]] ||
                error "expected limit_uid 0, found $offset"
@@ -2450,21 +2602,21 @@ test_27ab() { #LU-18109
        stopall || error "failed to unmount servers"
        setupall || error "failed to remount servers"
 
-       offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset |
+       offset=$(do_facet mgs $LCTL get_param nodemap.$nm1.offset |
                 grep start_uid)
        [[ "$offset" == *"start_uid: 0"* ]] ||
                error "expected start_uid 0, found $offset after remounting"
 
-       offset=$(do_facet mgs $LCTL get_param nodemap.Test18109.offset |
+       offset=$(do_facet mgs $LCTL get_param nodemap.$nm1.offset |
                 grep limit_uid)
        [[ "$offset" == *"limit_uid: 0"* ]] ||
                error "expected limit_uid 0, found $offset after remounting"
 
-       do_facet mgs $LCTL nodemap_del Test18109 ||
-               error "failed to remove nodemap Test18109"
+       do_facet mgs $LCTL nodemap_del $nm1 ||
+               error "failed to remove nodemap $nm1"
 
-       do_facet mgs $LCTL nodemap_del OffsetTest ||
-               error "failed to remove nodemap OffsetTest"
+       do_facet mgs $LCTL nodemap_del $nm2 ||
+               error "failed to remove nodemap $nm2"
 }
 run_test 27ab "test nodemap idmap offset"