Whamcloud - gitweb
LU-12580 lov: fix out of bound usercopy
[fs/lustre-release.git] / lustre / lov / lov_pack.c
index 3fe19fe..60d530b 100644 (file)
@@ -159,8 +159,8 @@ ssize_t lov_lsm_pack_v1v3(const struct lov_stripe_md *lsm, void *buf,
        lmmv1->lmm_layout_gen = cpu_to_le16(lsm->lsm_layout_gen);
 
        if (lsm->lsm_magic == LOV_MAGIC_V3) {
-               CLASSERT(sizeof(lsm->lsm_entries[0]->lsme_pool_name) ==
-                        sizeof(lmmv3->lmm_pool_name));
+               BUILD_BUG_ON(sizeof(lsm->lsm_entries[0]->lsme_pool_name) !=
+                                   sizeof(lmmv3->lmm_pool_name));
                strlcpy(lmmv3->lmm_pool_name,
                        lsm->lsm_entries[0]->lsme_pool_name,
                        sizeof(lmmv3->lmm_pool_name));
@@ -183,6 +183,28 @@ ssize_t lov_lsm_pack_v1v3(const struct lov_stripe_md *lsm, void *buf,
        RETURN(lmm_size);
 }
 
+ssize_t lov_lsm_pack_foreign(const struct lov_stripe_md *lsm, void *buf,
+                            size_t buf_size)
+{
+       struct lov_foreign_md *lfm = buf;
+       size_t lfm_size;
+
+       lfm_size = lsm->lsm_foreign_size;
+
+       if (buf_size == 0)
+               RETURN(lfm_size);
+
+       if (buf_size < lfm_size)
+               RETURN(-ERANGE);
+
+       /* full foreign LOV is already avail in its cache
+        * no need to translate format fields to little-endian
+        */
+       memcpy(lfm, lsm_foreign(lsm), lsm->lsm_foreign_size);
+
+       RETURN(lfm_size);
+}
+
 ssize_t lov_lsm_pack(const struct lov_stripe_md *lsm, void *buf,
                     size_t buf_size)
 {
@@ -200,6 +222,9 @@ ssize_t lov_lsm_pack(const struct lov_stripe_md *lsm, void *buf,
        if (lsm->lsm_magic == LOV_MAGIC_V1 || lsm->lsm_magic == LOV_MAGIC_V3)
                return lov_lsm_pack_v1v3(lsm, buf, buf_size);
 
+       if (lsm->lsm_magic == LOV_MAGIC_FOREIGN)
+               return lov_lsm_pack_foreign(lsm, buf, buf_size);
+
        lmm_size = lov_comp_md_size(lsm);
        if (buf_size == 0)
                RETURN(lmm_size);
@@ -362,16 +387,18 @@ int lov_getstripe(const struct lu_env *env, struct lov_object *obj,
 {
        /* we use lov_user_md_v3 because it is larger than lov_user_md_v1 */
        struct lov_mds_md *lmmk, *lmm;
+       struct lov_foreign_md *lfm;
        struct lov_user_md_v1 lum;
-       size_t lmmk_size;
-       ssize_t lmm_size, lum_size = 0;
+       size_t lmmk_size, lum_size = 0;
+       ssize_t lmm_size;
        static bool printed;
        int rc = 0;
 
        ENTRY;
 
        if (lsm->lsm_magic != LOV_MAGIC_V1 && lsm->lsm_magic != LOV_MAGIC_V3 &&
-           lsm->lsm_magic != LOV_MAGIC_COMP_V1) {
+           lsm->lsm_magic != LOV_MAGIC_COMP_V1 &&
+           lsm->lsm_magic != LOV_MAGIC_FOREIGN) {
                CERROR("bad LSM MAGIC: 0x%08X != 0x%08X nor 0x%08X\n",
                       lsm->lsm_magic, LOV_MAGIC_V1, LOV_MAGIC_V3);
                GOTO(out, rc = -EIO);
@@ -405,6 +432,12 @@ int lov_getstripe(const struct lu_env *env, struct lov_object *obj,
                } else if (lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_COMP_V1)) {
                        lustre_swab_lov_comp_md_v1(
                                        (struct lov_comp_md_v1 *)lmmk);
+               } else if (lmmk->lmm_magic == cpu_to_le32(LOV_MAGIC_FOREIGN)) {
+                       lfm = (struct lov_foreign_md *)lmmk;
+                       __swab32s(&lfm->lfm_magic);
+                       __swab32s(&lfm->lfm_length);
+                       __swab32s(&lfm->lfm_type);
+                       __swab32s(&lfm->lfm_flags);
                }
        }
 
@@ -412,8 +445,9 @@ int lov_getstripe(const struct lu_env *env, struct lov_object *obj,
         * Legacy appication passes limited buffer, we need to figure out
         * the user buffer size by the passed in lmm_stripe_count.
         */
-       if (copy_from_user(&lum, lump, sizeof(struct lov_user_md_v1)))
-               GOTO(out_free, rc = -EFAULT);
+       if (lsm->lsm_magic != LOV_MAGIC_FOREIGN)
+               if (copy_from_user(&lum, lump, sizeof(struct lov_user_md_v1)))
+                       GOTO(out_free, rc = -EFAULT);
 
        if (lum.lmm_magic == LOV_USER_MAGIC_V1 ||
            lum.lmm_magic == LOV_USER_MAGIC_V3)
@@ -454,10 +488,11 @@ int lov_getstripe(const struct lu_env *env, struct lov_object *obj,
                                i--;
                        comp_md = (struct lov_mds_md *)((char *)comp_v1 +
                                        comp_v1->lcm_entries[i].lcme_offset);
+                       lum_size = comp_v1->lcm_entries[i].lcme_size;
                }
 
                lmm = comp_md;
-               lmm_size = lum_size;
+               lmm_size = min(lum_size, lmmk_size);
        } else {
                lmm = lmmk;
                lmm_size = lmmk_size;