/* Return: 0 if succeeded, -ERR if failed. */
static int do_write_bitmap(struct feat_fd *ff, unsigned long *set, u64 size)
{
- u64 *p = (u64 *) set;
+ size_t byte_size = BITS_TO_LONGS(size) * sizeof(unsigned long);
int i, ret;
ret = do_write(ff, &size, sizeof(size));
if (ret < 0)
return ret;
+ /*
+ * The on-disk format uses u64 elements, but the in-memory bitmap
+ * uses unsigned long, which is only 4 bytes on 32-bit architectures.
+ * Copy with bounded size so the last element doesn't read past the
+ * bitmap allocation when BITS_TO_LONGS(size) is odd.
+ */
for (i = 0; (u64) i < BITS_TO_U64(size); i++) {
- ret = do_write(ff, p + i, sizeof(*p));
+ u64 val = 0;
+ size_t off = i * sizeof(val);
+
+ memcpy(&val, (char *)set + off, min(sizeof(val), byte_size - off));
+ ret = do_write(ff, &val, sizeof(val));
if (ret < 0)
return ret;
}
if (ret)
return ret;
- set = bitmap_zalloc(size);
+ /* Bitmap APIs use int for nbits; reject u64 values that truncate. */
+ if (size > INT_MAX ||
+ BITS_TO_U64(size) > (ff->size - ff->offset) / sizeof(u64)) {
+ pr_debug("do_read_bitmap: size %" PRIu64 " exceeds section bounds\n", size);
+ return -1;
+ }
+
+ /*
+ * bitmap_zalloc() allocates in unsigned long units, which are only
+ * 4 bytes on 32-bit architectures. The read loop below casts the
+ * buffer to u64 * and writes 8-byte elements, so allocate in u64
+ * units to ensure the buffer is large enough.
+ */
+ set = calloc(BITS_TO_U64(size), sizeof(u64));
if (!set)
return -ENOMEM;
return -1;
}
- if (ff->size < 3 * sizeof(u64) + nr * 2 * sizeof(u64)) {
+ /* Per node: node_id(u64) + mem_size(u64) + bitmap_nr_bits(u64) */
+ if (ff->size < 3 * sizeof(u64) + nr * 3 * sizeof(u64)) {
pr_err("Invalid HEADER_MEM_TOPOLOGY: section too small (%zu) for %llu nodes\n",
ff->size, (unsigned long long)nr);
return -1;
out:
if (ret)
- free(nodes);
+ memory_node__delete_nodes(nodes, nr);
return ret;
}