Whamcloud - gitweb
LU-13717 sec: limit hard links to linkEA size for enc files 87/43387/4
authorSebastien Buisson <sbuisson@ddn.com>
Mon, 19 Oct 2020 14:23:05 +0000 (23:23 +0900)
committerOleg Drokin <green@whamcloud.com>
Wed, 2 Jun 2021 17:48:40 +0000 (17:48 +0000)
Some operations on encrypted files require to identify all names for
files having the same FID. For instance, for lookup, getattr or unlink
on encrypted files without the encryption key, we need to perform an
operation by FID instead of the actual name.
In order to make operations by FID unambiguous on server side, we
decide to limit the number of possible hard links for encrypted files,
to what the linkEA can contain.
Currently linkEA stores 4KiB of links, that is 14 NAME_MAX links, or
119 16-byte names.

Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I20a01874899f95b2ff61e05b2aa6851d135633e8
Reviewed-on: https://review.whamcloud.com/43387
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Lai Siyao <lai.siyao@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
Reviewed-by: James Simmons <jsimmons@infradead.org>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
lustre/include/lustre_linkea.h
lustre/lfsck/lfsck_namespace.c
lustre/mdd/mdd_dir.c
lustre/obdclass/linkea.c
lustre/tests/sanity-sec.sh

index 3bf6e2b..422a17c 100644 (file)
@@ -61,8 +61,9 @@ void linkea_entry_unpack(const struct link_ea_entry *lee, int *reclen,
 int linkea_entry_pack(struct link_ea_entry *lee, const struct lu_name *lname,
                      const struct lu_fid *pfid);
 int linkea_add_buf(struct linkea_data *ldata, const struct lu_name *lname,
-                  const struct lu_fid *pfid);
-void linkea_del_buf(struct linkea_data *ldata, const struct lu_name *lname);
+                  const struct lu_fid *pfid, bool err_on_overflow);
+void linkea_del_buf(struct linkea_data *ldata, const struct lu_name *lname,
+                   bool is_encrypted);
 int linkea_links_new(struct linkea_data *ldata, struct lu_buf *buf,
                     const struct lu_name *cname, const struct lu_fid *pfid);
 int linkea_overflow_shrink(struct linkea_data *ldata);
index a5725d7..cd25883 100644 (file)
@@ -830,7 +830,7 @@ static void lfsck_linkea_del_buf(struct linkea_data *ldata,
 
                ldata->ld_lee = NULL;
        } else {
-               linkea_del_buf(ldata, lname);
+               linkea_del_buf(ldata, lname, false);
        }
 }
 
@@ -5883,7 +5883,7 @@ nodata:
                                GOTO(stop, rc);
                }
 
-               rc = linkea_add_buf(&ldata, cname, pfid);
+               rc = linkea_add_buf(&ldata, cname, pfid, false);
                if (rc == 0)
                        rc = lfsck_links_write(env, obj, &ldata, handle);
                if (rc != 0)
index 0fb1374..451fd1d 100644 (file)
@@ -1069,6 +1069,8 @@ static int __mdd_links_add(const struct lu_env *env,
                           const struct lu_fid *pfid,
                           int first, int check)
 {
+       /* cattr is set in mdd_link */
+       struct lu_attr *cattr = MDD_ENV_VAR(env, cattr);
        int rc;
 
        if (ldata->ld_leh == NULL) {
@@ -1096,13 +1098,20 @@ static int __mdd_links_add(const struct lu_env *env,
 
                *tfid = *pfid;
                tfid->f_ver = ~0;
-               linkea_add_buf(ldata, lname, tfid);
+               linkea_add_buf(ldata, lname, tfid, false);
        }
 
        if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_LINKEA_MORE2))
-               linkea_add_buf(ldata, lname, pfid);
+               linkea_add_buf(ldata, lname, pfid, false);
 
-       return linkea_add_buf(ldata, lname, pfid);
+       /* For encrypted file, we want to limit number of hard links to what
+        * linkEA can contain. So ask to return error in case of overflow.
+        * Currently linkEA stores 4KiB of links, that is 14 NAME_MAX links,
+        * or 119 16-byte names.
+        */
+       return linkea_add_buf(ldata, lname, pfid,
+                             cattr->la_valid & LA_FLAGS &&
+                             cattr->la_flags & LUSTRE_ENCRYPT_FL);
 }
 
 static int __mdd_links_del(const struct lu_env *env,
@@ -1111,6 +1120,8 @@ static int __mdd_links_del(const struct lu_env *env,
                           const struct lu_name *lname,
                           const struct lu_fid *pfid)
 {
+       /* cattr is set in mdd_link */
+       struct lu_attr *cattr = MDD_ENV_VAR(env, cattr);
        int rc;
 
        if (ldata->ld_leh == NULL) {
@@ -1123,7 +1134,9 @@ static int __mdd_links_del(const struct lu_env *env,
        if (rc)
                return rc;
 
-       linkea_del_buf(ldata, lname);
+       linkea_del_buf(ldata, lname,
+                      cattr->la_valid & LA_FLAGS &&
+                      cattr->la_flags & LUSTRE_ENCRYPT_FL);
        return 0;
 }
 
index cf17a50..24cb1eb 100644 (file)
@@ -130,7 +130,7 @@ EXPORT_SYMBOL(linkea_entry_unpack);
  * Add a record to the end of link ea buf
  **/
 int linkea_add_buf(struct linkea_data *ldata, const struct lu_name *lname,
-                  const struct lu_fid *pfid)
+                  const struct lu_fid *pfid, bool err_on_overflow)
 {
        struct link_ea_header *leh = ldata->ld_leh;
        int reclen;
@@ -154,7 +154,7 @@ int linkea_add_buf(struct linkea_data *ldata, const struct lu_name *lname,
                CDEBUG(D_INODE, "No enough space to hold linkea entry '"
                       DFID": %.*s' at %u\n", PFID(pfid), lname->ln_namelen,
                       lname->ln_name, leh->leh_overflow_time);
-               return 0;
+               return err_on_overflow ? -EOVERFLOW : 0;
        }
 
        if (leh->leh_len + reclen > ldata->ld_buf->lb_len) {
@@ -169,14 +169,20 @@ int linkea_add_buf(struct linkea_data *ldata, const struct lu_name *lname,
        ldata->ld_reclen = linkea_entry_pack(ldata->ld_lee, lname, pfid);
        leh->leh_len += ldata->ld_reclen;
        leh->leh_reccount++;
-       CDEBUG(D_INODE, "New link_ea name '"DFID":%.*s' is added\n",
-              PFID(pfid), lname->ln_namelen, lname->ln_name);
+       if (err_on_overflow)
+               CDEBUG(D_INODE,
+                      "New link_ea name '"DFID":<encrypted (%d)>' is added\n",
+                      PFID(pfid), lname->ln_namelen);
+       else
+               CDEBUG(D_INODE, "New link_ea name '"DFID":%.*s' is added\n",
+                      PFID(pfid), lname->ln_namelen, lname->ln_name);
        return 0;
 }
 EXPORT_SYMBOL(linkea_add_buf);
 
 /** Del the current record from the link ea buf */
-void linkea_del_buf(struct linkea_data *ldata, const struct lu_name *lname)
+void linkea_del_buf(struct linkea_data *ldata, const struct lu_name *lname,
+                   bool is_encrypted)
 {
        LASSERT(ldata->ld_leh != NULL && ldata->ld_lee != NULL);
        LASSERT(ldata->ld_leh->leh_reccount > 0);
@@ -186,8 +192,13 @@ void linkea_del_buf(struct linkea_data *ldata, const struct lu_name *lname)
        memmove(ldata->ld_lee, (char *)ldata->ld_lee + ldata->ld_reclen,
                (char *)ldata->ld_leh + ldata->ld_leh->leh_len -
                (char *)ldata->ld_lee);
-       CDEBUG(D_INODE, "Old link_ea name '%.*s' is removed\n",
-              lname->ln_namelen, lname->ln_name);
+       if (is_encrypted)
+               CDEBUG(D_INODE,
+                      "Old link_ea name '<encrypted (%d)>' is removed\n",
+                      lname->ln_namelen);
+       else
+               CDEBUG(D_INODE, "Old link_ea name '%.*s' is removed\n",
+                      lname->ln_namelen, lname->ln_name);
 
        if ((char *)ldata->ld_lee >= ((char *)ldata->ld_leh +
                                      ldata->ld_leh->leh_len))
@@ -202,7 +213,7 @@ int linkea_links_new(struct linkea_data *ldata, struct lu_buf *buf,
 
        rc = linkea_data_new(ldata, buf);
        if (!rc)
-               rc = linkea_add_buf(ldata, cname, pfid);
+               rc = linkea_add_buf(ldata, cname, pfid, false);
 
        return rc;
 }
index b887dcb..3277995 100755 (executable)
@@ -3404,6 +3404,13 @@ test_47() {
                error "link from encrypted to unencrypted dir should succeed"
        rm -f $tmpfile
 
+       # check we are limited in the number of hard links
+       # we can create for encrypted files, to what can fit into LinkEA
+       for i in $(seq 1 160); do
+               ln $testfile2 ${testfile}_$i || break
+       done
+       [ $i -lt 160 ] || error "hard link $i should fail"
+
        mrename $testfile2 $tmpfile &&
                error "rename from encrypted to unencrypted dir should fail"
        touch $tmpfile