From 4829fb05c6ca672775701de85bc495344ac619e9 Mon Sep 17 00:00:00 2001 From: Lai Siyao Date: Mon, 23 Jul 2018 05:45:23 +0800 Subject: [PATCH] LU-11201 lfsck: check linkea entry validity 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 Change-Id: I8e1890ed64fab38b85149ebbfecce04caaf41e17 Reviewed-by: Andreas Dilger Reviewed-by: Hongchao Zhang Signed-off-by: Minh Diep Reviewed-on: https://review.whamcloud.com/33078 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: John L. Hammond --- lustre/lfsck/lfsck_namespace.c | 48 ++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/lustre/lfsck/lfsck_namespace.c b/lustre/lfsck/lfsck_namespace.c index 36098bb..ca041bf 100644 --- a/lustre/lfsck/lfsck_namespace.c +++ b/lustre/lfsck/lfsck_namespace.c @@ -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; -- 1.8.3.1