Whamcloud - gitweb
LU-11201 lfsck: check linkea entry validity 78/33078/2
authorLai Siyao <lai.siyao@intel.com>
Sun, 22 Jul 2018 21:45:23 +0000 (05:45 +0800)
committerJohn L. Hammond <jhammond@whamcloud.com>
Tue, 11 Sep 2018 20:36:44 +0000 (20:36 +0000)
Invalid linkea data may lead to dead loop in linkea iteration, check
linkea entry validity on unpack, and if entry is not unpacked, check
entry length validity.

Test-Parameters: trivial mdscount=2 mdtcount=4 testlist=sanity-lfsck

Lustre-change: https://review.whamcloud.com/32958
Lustre-commit: a5441a717c3a97071494ff51cfb72a117d12d96e

Signed-off-by: Lai Siyao <lai.siyao@whamcloud.com>
Change-Id: I8e1890ed64fab38b85149ebbfecce04caaf41e17
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Hongchao Zhang <hongchao@whamcloud.com>
Signed-off-by: Minh Diep <mdiep@whamcloud.com>
Reviewed-on: https://review.whamcloud.com/33078
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: John L. Hammond <jhammond@whamcloud.com>
lustre/lfsck/lfsck_namespace.c

index 36098bb..ca041bf 100644 (file)
@@ -757,19 +757,41 @@ again:
        return rc;
 }
 
+static inline bool linkea_reclen_is_valid(const struct linkea_data *ldata)
+{
+       if (ldata->ld_reclen <= 0)
+               return false;
+
+       if ((char *)ldata->ld_lee + ldata->ld_reclen >
+           (char *)ldata->ld_leh + ldata->ld_leh->leh_len)
+               return false;
+
+       return true;
+}
+
+static inline bool linkea_entry_is_valid(const struct linkea_data *ldata,
+                                        const struct lu_name *cname,
+                                        const struct lu_fid *pfid)
+{
+       if (!linkea_reclen_is_valid(ldata))
+               return false;
+
+       if (cname->ln_namelen <= 0 || cname->ln_namelen > NAME_MAX)
+               return false;
+
+       if (!fid_is_sane(pfid))
+               return false;
+
+       return true;
+}
+
 static int lfsck_namespace_unpack_linkea_entry(struct linkea_data *ldata,
                                               struct lu_name *cname,
                                               struct lu_fid *pfid,
                                               char *buf, const int buflen)
 {
        linkea_entry_unpack(ldata->ld_lee, &ldata->ld_reclen, cname, pfid);
-       if (unlikely(ldata->ld_reclen <= 0 ||
-                    ldata->ld_reclen + sizeof(struct link_ea_header) >
-                       ldata->ld_leh->leh_len ||
-                    cname->ln_namelen <= 0 ||
-                    cname->ln_namelen > NAME_MAX ||
-                    cname->ln_namelen >= buflen ||
-                    !fid_is_sane(pfid)))
+       if (unlikely(!linkea_entry_is_valid(ldata, cname, pfid)))
                return -EINVAL;
 
        /* To guarantee the 'name' is terminated with '0'. */
@@ -787,9 +809,7 @@ static void lfsck_linkea_del_buf(struct linkea_data *ldata,
 
        /* If current record is corrupted, all the subsequent
         * records will be dropped. */
-       if (unlikely(ldata->ld_reclen <= 0 ||
-                    ldata->ld_reclen + sizeof(struct link_ea_header) >
-                       ldata->ld_leh->leh_len)) {
+       if (unlikely(!linkea_reclen_is_valid(ldata))) {
                void *ptr = ldata->ld_lee;
 
                ldata->ld_leh->leh_len = sizeof(struct link_ea_header);
@@ -827,7 +847,10 @@ static int lfsck_namespace_filter_linkea_entry(struct linkea_data *ldata,
        while (ldata->ld_lee != NULL) {
                ldata->ld_reclen = (ldata->ld_lee->lee_reclen[0] << 8) |
                                   ldata->ld_lee->lee_reclen[1];
-               if (unlikely(ldata->ld_reclen == oldlen &&
+               if (unlikely(!linkea_reclen_is_valid(ldata))) {
+                       lfsck_linkea_del_buf(ldata, NULL);
+                       LASSERT(ldata->ld_lee == NULL);
+               } else if (unlikely(ldata->ld_reclen == oldlen &&
                             memcmp(ldata->ld_lee, oldlee, oldlen) == 0)) {
                        repeated++;
                        if (!remove)
@@ -6516,6 +6539,9 @@ int lfsck_links_get_first(const struct lu_env *env, struct dt_object *obj,
 
        linkea_first_entry(&ldata);
        linkea_entry_unpack(ldata.ld_lee, &ldata.ld_reclen, cname, pfid);
+       if (!linkea_entry_is_valid(&ldata, cname, pfid))
+               return -EINVAL;
+
        /* To guarantee the 'name' is terminated with '0'. */
        memcpy(name, cname->ln_name, cname->ln_namelen);
        name[cname->ln_namelen] = 0;