Whamcloud - gitweb
LU-12580 lov: fix out of bound usercopy
[fs/lustre-release.git] / lustre / lov / lov_pack.c
index da41b2c..60d530b 100644 (file)
@@ -53,13 +53,13 @@ void lov_dump_lmm_common(int level, void *lmmp)
        struct ost_id oi;
 
        lmm_oi_le_to_cpu(&oi, &lmm->lmm_oi);
-       CDEBUG(level, "objid "DOSTID", magic 0x%08x, pattern %#x\n",
-              POSTID(&oi), le32_to_cpu(lmm->lmm_magic),
-              le32_to_cpu(lmm->lmm_pattern));
-       CDEBUG(level, "stripe_size %u, stripe_count %u, layout_gen %u\n",
-              le32_to_cpu(lmm->lmm_stripe_size),
-              le16_to_cpu(lmm->lmm_stripe_count),
-              le16_to_cpu(lmm->lmm_layout_gen));
+       CDEBUG_LIMIT(level, "objid "DOSTID", magic 0x%08x, pattern %#x\n",
+                    POSTID(&oi), le32_to_cpu(lmm->lmm_magic),
+                    le32_to_cpu(lmm->lmm_pattern));
+       CDEBUG_LIMIT(level, "stripe_size %u, stripe_count %u, layout_gen %u\n",
+                    le32_to_cpu(lmm->lmm_stripe_size),
+                    le16_to_cpu(lmm->lmm_stripe_count),
+                    le16_to_cpu(lmm->lmm_layout_gen));
 }
 
 static void lov_dump_lmm_objects(int level, struct lov_ost_data *lod,
@@ -68,8 +68,9 @@ static void lov_dump_lmm_objects(int level, struct lov_ost_data *lod,
        int i;
 
        if (stripe_count > LOV_V1_INSANE_STRIPE_COUNT) {
-               CDEBUG(level, "bad stripe_count %u > max_stripe_count %u\n",
-                      stripe_count, LOV_V1_INSANE_STRIPE_COUNT);
+               CDEBUG_LIMIT(level,
+                            "bad stripe_count %u > max_stripe_count %u\n",
+                            stripe_count, LOV_V1_INSANE_STRIPE_COUNT);
                return;
        }
 
@@ -77,8 +78,8 @@ static void lov_dump_lmm_objects(int level, struct lov_ost_data *lod,
                struct ost_id oi;
 
                ostid_le_to_cpu(&lod->l_ost_oi, &oi);
-               CDEBUG(level, "stripe %u idx %u subobj "DOSTID"\n", i,
-                      le32_to_cpu(lod->l_ost_idx), POSTID(&oi));
+               CDEBUG_LIMIT(level, "stripe %u idx %u subobj "DOSTID"\n", i,
+                            le32_to_cpu(lod->l_ost_idx), POSTID(&oi));
        }
 }
 
@@ -92,7 +93,7 @@ void lov_dump_lmm_v1(int level, struct lov_mds_md_v1 *lmm)
 void lov_dump_lmm_v3(int level, struct lov_mds_md_v3 *lmm)
 {
        lov_dump_lmm_common(level, lmm);
-       CDEBUG(level, "pool_name "LOV_POOLNAMEF"\n", lmm->lmm_pool_name);
+       CDEBUG_LIMIT(level, "pool_name "LOV_POOLNAMEF"\n", lmm->lmm_pool_name);
        lov_dump_lmm_objects(level, lmm->lmm_objects,
                             le16_to_cpu(lmm->lmm_stripe_count));
 }
@@ -110,8 +111,8 @@ void lov_dump_lmm(int level, void *lmm)
                lov_dump_lmm_v3(level, (struct lov_mds_md_v3 *)lmm);
                break;
        default:
-               CDEBUG(level, "unrecognized lmm_magic %x, assuming %x\n",
-                      magic, LOV_MAGIC_V1);
+               CDEBUG_LIMIT(level, "unrecognized lmm_magic %x, assuming %x\n",
+                            magic, LOV_MAGIC_V1);
                lov_dump_lmm_common(level, lmm);
                break;
        }
@@ -158,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));
@@ -182,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)
 {
@@ -199,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);
@@ -361,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);
@@ -404,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);
                }
        }
 
@@ -411,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)
@@ -453,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;