Add additional verification of size fields and strings (#18623)
- Check for size fields that convert to smaller integers. - Explicitly terminate bootenv string. - Initialize variables that could be returned in an error case. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Chris Longros <chris.longros@gmail.com> Reviewed-by: Alexander Motin <alexander.motin@TrueNAS.com> Signed-off-by: Tony Hutter <hutter2@llnl.gov> Closes #18623
This commit is contained in:
+31
-13
@@ -2901,16 +2901,20 @@ receive_read_record(dmu_recv_cookie_t *drc)
|
|||||||
{
|
{
|
||||||
struct drr_object *drro =
|
struct drr_object *drro =
|
||||||
&drc->drc_rrd->header.drr_u.drr_object;
|
&drc->drc_rrd->header.drr_u.drr_object;
|
||||||
uint32_t size = DRR_OBJECT_PAYLOAD_SIZE(drro);
|
uint32_t size;
|
||||||
void *buf = NULL;
|
void *buf = NULL;
|
||||||
dmu_object_info_t doi;
|
dmu_object_info_t doi;
|
||||||
|
|
||||||
|
size = DRR_OBJECT_PAYLOAD_SIZE(drro);
|
||||||
|
if (size > SPA_MAXBLOCKSIZE)
|
||||||
|
return (SET_ERROR(ERANGE));
|
||||||
|
|
||||||
if (size != 0)
|
if (size != 0)
|
||||||
buf = kmem_zalloc(size, KM_SLEEP);
|
buf = vmem_zalloc(size, KM_SLEEP);
|
||||||
|
|
||||||
err = receive_read_payload_and_next_header(drc, size, buf);
|
err = receive_read_payload_and_next_header(drc, size, buf);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
kmem_free(buf, size);
|
vmem_free(buf, size);
|
||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
err = dmu_object_info(drc->drc_os, drro->drr_object, &doi);
|
err = dmu_object_info(drc->drc_os, drro->drr_object, &doi);
|
||||||
@@ -2934,7 +2938,11 @@ receive_read_record(dmu_recv_cookie_t *drc)
|
|||||||
case DRR_WRITE:
|
case DRR_WRITE:
|
||||||
{
|
{
|
||||||
struct drr_write *drrw = &drc->drc_rrd->header.drr_u.drr_write;
|
struct drr_write *drrw = &drc->drc_rrd->header.drr_u.drr_write;
|
||||||
int size = DRR_WRITE_PAYLOAD_SIZE(drrw);
|
uint64_t size = DRR_WRITE_PAYLOAD_SIZE(drrw);
|
||||||
|
|
||||||
|
if (size > SPA_MAXBLOCKSIZE)
|
||||||
|
return (SET_ERROR(ERANGE));
|
||||||
|
|
||||||
abd_t *abd = abd_alloc_linear(size, B_FALSE);
|
abd_t *abd = abd_alloc_linear(size, B_FALSE);
|
||||||
err = receive_read_payload_and_next_header(drc, size,
|
err = receive_read_payload_and_next_header(drc, size,
|
||||||
abd_to_buf(abd));
|
abd_to_buf(abd));
|
||||||
@@ -2951,12 +2959,18 @@ receive_read_record(dmu_recv_cookie_t *drc)
|
|||||||
{
|
{
|
||||||
struct drr_write_embedded *drrwe =
|
struct drr_write_embedded *drrwe =
|
||||||
&drc->drc_rrd->header.drr_u.drr_write_embedded;
|
&drc->drc_rrd->header.drr_u.drr_write_embedded;
|
||||||
uint32_t size = P2ROUNDUP(drrwe->drr_psize, 8);
|
uint32_t size;
|
||||||
void *buf = kmem_zalloc(size, KM_SLEEP);
|
void *buf;
|
||||||
|
|
||||||
|
size = P2ROUNDUP(drrwe->drr_psize, 8);
|
||||||
|
if (size > SPA_MAXBLOCKSIZE)
|
||||||
|
return (SET_ERROR(ERANGE));
|
||||||
|
|
||||||
|
buf = vmem_zalloc(size, KM_SLEEP);
|
||||||
|
|
||||||
err = receive_read_payload_and_next_header(drc, size, buf);
|
err = receive_read_payload_and_next_header(drc, size, buf);
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
kmem_free(buf, size);
|
vmem_free(buf, size);
|
||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2985,7 +2999,11 @@ receive_read_record(dmu_recv_cookie_t *drc)
|
|||||||
case DRR_SPILL:
|
case DRR_SPILL:
|
||||||
{
|
{
|
||||||
struct drr_spill *drrs = &drc->drc_rrd->header.drr_u.drr_spill;
|
struct drr_spill *drrs = &drc->drc_rrd->header.drr_u.drr_spill;
|
||||||
int size = DRR_SPILL_PAYLOAD_SIZE(drrs);
|
uint64_t size = DRR_SPILL_PAYLOAD_SIZE(drrs);
|
||||||
|
|
||||||
|
if (size > SPA_MAXBLOCKSIZE)
|
||||||
|
return (SET_ERROR(ERANGE));
|
||||||
|
|
||||||
abd_t *abd = abd_alloc_linear(size, B_FALSE);
|
abd_t *abd = abd_alloc_linear(size, B_FALSE);
|
||||||
err = receive_read_payload_and_next_header(drc, size,
|
err = receive_read_payload_and_next_header(drc, size,
|
||||||
abd_to_buf(abd));
|
abd_to_buf(abd));
|
||||||
@@ -3136,7 +3154,7 @@ receive_process_record(struct receive_writer_arg *rwa,
|
|||||||
abd_free(rrd->abd);
|
abd_free(rrd->abd);
|
||||||
rrd->abd = NULL;
|
rrd->abd = NULL;
|
||||||
} else if (rrd->payload != NULL) {
|
} else if (rrd->payload != NULL) {
|
||||||
kmem_free(rrd->payload, rrd->payload_size);
|
vmem_free(rrd->payload, rrd->payload_size);
|
||||||
rrd->payload = NULL;
|
rrd->payload = NULL;
|
||||||
}
|
}
|
||||||
return (0);
|
return (0);
|
||||||
@@ -3150,7 +3168,7 @@ receive_process_record(struct receive_writer_arg *rwa,
|
|||||||
rrd->abd = NULL;
|
rrd->abd = NULL;
|
||||||
rrd->payload = NULL;
|
rrd->payload = NULL;
|
||||||
} else if (rrd->payload != NULL) {
|
} else if (rrd->payload != NULL) {
|
||||||
kmem_free(rrd->payload, rrd->payload_size);
|
vmem_free(rrd->payload, rrd->payload_size);
|
||||||
rrd->payload = NULL;
|
rrd->payload = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3163,7 +3181,7 @@ receive_process_record(struct receive_writer_arg *rwa,
|
|||||||
{
|
{
|
||||||
struct drr_object *drro = &rrd->header.drr_u.drr_object;
|
struct drr_object *drro = &rrd->header.drr_u.drr_object;
|
||||||
err = receive_object(rwa, drro, rrd->payload);
|
err = receive_object(rwa, drro, rrd->payload);
|
||||||
kmem_free(rrd->payload, rrd->payload_size);
|
vmem_free(rrd->payload, rrd->payload_size);
|
||||||
rrd->payload = NULL;
|
rrd->payload = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3201,7 +3219,7 @@ receive_process_record(struct receive_writer_arg *rwa,
|
|||||||
struct drr_write_embedded *drrwe =
|
struct drr_write_embedded *drrwe =
|
||||||
&rrd->header.drr_u.drr_write_embedded;
|
&rrd->header.drr_u.drr_write_embedded;
|
||||||
err = receive_write_embedded(rwa, drrwe, rrd->payload);
|
err = receive_write_embedded(rwa, drrwe, rrd->payload);
|
||||||
kmem_free(rrd->payload, rrd->payload_size);
|
vmem_free(rrd->payload, rrd->payload_size);
|
||||||
rrd->payload = NULL;
|
rrd->payload = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3270,7 +3288,7 @@ receive_writer_thread(void *arg)
|
|||||||
rrd->abd = NULL;
|
rrd->abd = NULL;
|
||||||
rrd->payload = NULL;
|
rrd->payload = NULL;
|
||||||
} else if (rrd->payload != NULL) {
|
} else if (rrd->payload != NULL) {
|
||||||
kmem_free(rrd->payload, rrd->payload_size);
|
vmem_free(rrd->payload, rrd->payload_size);
|
||||||
rrd->payload = NULL;
|
rrd->payload = NULL;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -1405,6 +1405,7 @@ vdev_label_read_bootenv(vdev_t *rvd, nvlist_t *bootenv)
|
|||||||
VB_NVLIST);
|
VB_NVLIST);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
vbe->vbe_bootenv[sizeof (vbe->vbe_bootenv) - 1] = '\0';
|
||||||
fnvlist_add_string(bootenv, FREEBSD_BOOTONCE, buf);
|
fnvlist_add_string(bootenv, FREEBSD_BOOTONCE, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7180,7 +7180,7 @@ zfs_ioc_space_snaps(const char *lastsnap, nvlist_t *innvl, nvlist_t *outnvl)
|
|||||||
dsl_pool_t *dp;
|
dsl_pool_t *dp;
|
||||||
dsl_dataset_t *new, *old;
|
dsl_dataset_t *new, *old;
|
||||||
const char *firstsnap;
|
const char *firstsnap;
|
||||||
uint64_t used, comp, uncomp;
|
uint64_t used = 0, comp = 0, uncomp = 0;
|
||||||
|
|
||||||
firstsnap = fnvlist_lookup_string(innvl, "firstsnap");
|
firstsnap = fnvlist_lookup_string(innvl, "firstsnap");
|
||||||
|
|
||||||
|
|||||||
@@ -86,10 +86,14 @@ zpl_get_file_info(dmu_object_type_t bonustype, const void *data,
|
|||||||
sa.sa_layout_info = BSWAP_16(sa.sa_layout_info);
|
sa.sa_layout_info = BSWAP_16(sa.sa_layout_info);
|
||||||
swap = B_TRUE;
|
swap = B_TRUE;
|
||||||
}
|
}
|
||||||
VERIFY3U(sa.sa_magic, ==, SA_MAGIC);
|
|
||||||
|
if (unlikely(sa.sa_magic != SA_MAGIC))
|
||||||
|
return (SET_ERROR(EINVAL));
|
||||||
|
|
||||||
int hdrsize = sa_hdrsize(&sa);
|
int hdrsize = sa_hdrsize(&sa);
|
||||||
VERIFY3U(hdrsize, >=, sizeof (sa_hdr_phys_t));
|
|
||||||
|
if (unlikely(hdrsize < sizeof (sa_hdr_phys_t)))
|
||||||
|
return (SET_ERROR(EINVAL));
|
||||||
|
|
||||||
uintptr_t data_after_hdr = (uintptr_t)data + hdrsize;
|
uintptr_t data_after_hdr = (uintptr_t)data + hdrsize;
|
||||||
zoi->zfi_user = *((uint64_t *)(data_after_hdr + SA_UID_OFFSET));
|
zoi->zfi_user = *((uint64_t *)(data_after_hdr + SA_UID_OFFSET));
|
||||||
|
|||||||
Reference in New Issue
Block a user