Skip to content

Commit 6f50f8e

Browse files
authored
zfs_log: add flex array fields to log record structs
ZIL log record structs (lr_XX_t) are frequently allocated with extra space after the struct to carry variable-sized "payload" items. Linux 6.10+ compiled with CONFIG_FORTIFY_SOURCE has been doing runtime bounds checking on memcpy() calls. Because these types had no indicator that they might use more space than their simple definition, __fortify_memcpy_chk will frequently complain about overruns eg: memcpy: detected field-spanning write (size 7) of single field "lr + 1" at zfs_log.c:425 (size 0) memcpy: detected field-spanning write (size 9) of single field "(char *)(lr + 1)" at zfs_log.c:593 (size 0) memcpy: detected field-spanning write (size 4) of single field "(char *)(lr + 1) + snamesize" at zfs_log.c:594 (size 0) memcpy: detected field-spanning write (size 7) of single field "lr + 1" at zfs_log.c:425 (size 0) memcpy: detected field-spanning write (size 9) of single field "(char *)(lr + 1)" at zfs_log.c:593 (size 0) memcpy: detected field-spanning write (size 4) of single field "(char *)(lr + 1) + snamesize" at zfs_log.c:594 (size 0) memcpy: detected field-spanning write (size 7) of single field "lr + 1" at zfs_log.c:425 (size 0) memcpy: detected field-spanning write (size 9) of single field "(char *)(lr + 1)" at zfs_log.c:593 (size 0) memcpy: detected field-spanning write (size 4) of single field "(char *)(lr + 1) + snamesize" at zfs_log.c:594 (size 0) To fix this, this commit adds flex array fields to all lr_XX_t structs that require them, and then uses those fields to access that end-of-struct area rather than more complicated casts and pointer addition. Sponsored-by: https://despairlabs.com/sponsor/ Reviewed-by: Alexander Motin <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: Rob Norris <[email protected]> Closes openzfs#16501 Closes openzfs#16539
1 parent ac8837d commit 6f50f8e

File tree

5 files changed

+162
-131
lines changed

5 files changed

+162
-131
lines changed

cmd/zdb/zdb_il.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ static void
6464
zil_prt_rec_create(zilog_t *zilog, int txtype, const void *arg)
6565
{
6666
(void) zilog;
67-
const lr_create_t *lr = arg;
67+
const lr_create_t *lrc = arg;
68+
const _lr_create_t *lr = &lrc->lr_create;
6869
time_t crtime = lr->lr_crtime[0];
6970
char *name, *link;
7071
lr_attr_t *lrattr;
@@ -121,7 +122,8 @@ static void
121122
zil_prt_rec_rename(zilog_t *zilog, int txtype, const void *arg)
122123
{
123124
(void) zilog, (void) txtype;
124-
const lr_rename_t *lr = arg;
125+
const lr_rename_t *lrr = arg;
126+
const _lr_rename_t *lr = &lrr->lr_rename;
125127
char *snm = (char *)(lr + 1);
126128
char *tnm = snm + strlen(snm) + 1;
127129

cmd/ztest.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1940,15 +1940,15 @@ ztest_verify_unused_bonus(dmu_buf_t *db, void *end, uint64_t obj,
19401940
static void
19411941
ztest_log_create(ztest_ds_t *zd, dmu_tx_t *tx, lr_create_t *lr)
19421942
{
1943-
char *name = (void *)(lr + 1); /* name follows lr */
1943+
char *name = (char *)&lr->lr_data[0]; /* name follows lr */
19441944
size_t namesize = strlen(name) + 1;
19451945
itx_t *itx;
19461946

19471947
if (zil_replaying(zd->zd_zilog, tx))
19481948
return;
19491949

19501950
itx = zil_itx_create(TX_CREATE, sizeof (*lr) + namesize);
1951-
memcpy(&itx->itx_lr + 1, &lr->lr_common + 1,
1951+
memcpy(&itx->itx_lr + 1, &lr->lr_create.lr_common + 1,
19521952
sizeof (*lr) + namesize - sizeof (lr_t));
19531953

19541954
zil_itx_assign(zd->zd_zilog, itx, tx);
@@ -1957,7 +1957,7 @@ ztest_log_create(ztest_ds_t *zd, dmu_tx_t *tx, lr_create_t *lr)
19571957
static void
19581958
ztest_log_remove(ztest_ds_t *zd, dmu_tx_t *tx, lr_remove_t *lr, uint64_t object)
19591959
{
1960-
char *name = (void *)(lr + 1); /* name follows lr */
1960+
char *name = (char *)&lr->lr_data[0]; /* name follows lr */
19611961
size_t namesize = strlen(name) + 1;
19621962
itx_t *itx;
19631963

@@ -2043,8 +2043,9 @@ static int
20432043
ztest_replay_create(void *arg1, void *arg2, boolean_t byteswap)
20442044
{
20452045
ztest_ds_t *zd = arg1;
2046-
lr_create_t *lr = arg2;
2047-
char *name = (void *)(lr + 1); /* name follows lr */
2046+
lr_create_t *lrc = arg2;
2047+
_lr_create_t *lr = &lrc->lr_create;
2048+
char *name = (char *)&lrc->lr_data[0]; /* name follows lr */
20482049
objset_t *os = zd->zd_os;
20492050
ztest_block_tag_t *bbt;
20502051
dmu_buf_t *db;
@@ -2122,7 +2123,7 @@ ztest_replay_create(void *arg1, void *arg2, boolean_t byteswap)
21222123
VERIFY0(zap_add(os, lr->lr_doid, name, sizeof (uint64_t), 1,
21232124
&lr->lr_foid, tx));
21242125

2125-
(void) ztest_log_create(zd, tx, lr);
2126+
(void) ztest_log_create(zd, tx, lrc);
21262127

21272128
dmu_tx_commit(tx);
21282129

@@ -2134,7 +2135,7 @@ ztest_replay_remove(void *arg1, void *arg2, boolean_t byteswap)
21342135
{
21352136
ztest_ds_t *zd = arg1;
21362137
lr_remove_t *lr = arg2;
2137-
char *name = (void *)(lr + 1); /* name follows lr */
2138+
char *name = (char *)&lr->lr_data[0]; /* name follows lr */
21382139
objset_t *os = zd->zd_os;
21392140
dmu_object_info_t doi;
21402141
dmu_tx_t *tx;
@@ -2188,9 +2189,9 @@ ztest_replay_write(void *arg1, void *arg2, boolean_t byteswap)
21882189
ztest_ds_t *zd = arg1;
21892190
lr_write_t *lr = arg2;
21902191
objset_t *os = zd->zd_os;
2191-
void *data = lr + 1; /* data follows lr */
2192+
uint8_t *data = &lr->lr_data[0]; /* data follows lr */
21922193
uint64_t offset, length;
2193-
ztest_block_tag_t *bt = data;
2194+
ztest_block_tag_t *bt = (ztest_block_tag_t *)data;
21942195
ztest_block_tag_t *bbt;
21952196
uint64_t gen, txg, lrtxg, crtxg;
21962197
dmu_object_info_t doi;
@@ -2649,7 +2650,8 @@ ztest_create(ztest_ds_t *zd, ztest_od_t *od, int count)
26492650
continue;
26502651
}
26512652

2652-
lr_create_t *lr = ztest_lr_alloc(sizeof (*lr), od->od_name);
2653+
lr_create_t *lrc = ztest_lr_alloc(sizeof (*lrc), od->od_name);
2654+
_lr_create_t *lr = &lrc->lr_create;
26532655

26542656
lr->lr_doid = od->od_dir;
26552657
lr->lr_foid = 0; /* 0 to allocate, > 0 to claim */
@@ -2733,7 +2735,7 @@ ztest_write(ztest_ds_t *zd, uint64_t object, uint64_t offset, uint64_t size,
27332735
lr->lr_blkoff = 0;
27342736
BP_ZERO(&lr->lr_blkptr);
27352737

2736-
memcpy(lr + 1, data, size);
2738+
memcpy(&lr->lr_data[0], data, size);
27372739

27382740
error = ztest_replay_write(zd, lr, B_FALSE);
27392741

include/sys/zil.h

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ typedef struct {
248248
uint32_t lr_attr_masksize; /* number of elements in array */
249249
uint32_t lr_attr_bitmap; /* First entry of array */
250250
/* remainder of array and additional lr_attr_end_t fields */
251+
uint8_t lr_attr_data[];
251252
} lr_attr_t;
252253

253254
/*
@@ -264,9 +265,14 @@ typedef struct {
264265
uint64_t lr_gen; /* generation (txg of creation) */
265266
uint64_t lr_crtime[2]; /* creation time */
266267
uint64_t lr_rdev; /* rdev of object to create */
268+
} _lr_create_t;
269+
270+
typedef struct {
271+
_lr_create_t lr_create; /* common create portion */
267272
/* name of object to create follows this */
268273
/* for symlinks, link content follows name */
269274
/* for creates with xvattr data, the name follows the xvattr info */
275+
uint8_t lr_data[];
270276
} lr_create_t;
271277

272278
/*
@@ -293,37 +299,45 @@ typedef struct {
293299
* and group will be in lr_create. Name follows ACL data.
294300
*/
295301
typedef struct {
296-
lr_create_t lr_create; /* common create portion */
302+
_lr_create_t lr_create; /* common create portion */
297303
uint64_t lr_aclcnt; /* number of ACEs in ACL */
298304
uint64_t lr_domcnt; /* number of unique domains */
299305
uint64_t lr_fuidcnt; /* number of real fuids */
300306
uint64_t lr_acl_bytes; /* number of bytes in ACL */
301307
uint64_t lr_acl_flags; /* ACL flags */
308+
uint8_t lr_data[];
302309
} lr_acl_create_t;
303310

304311
typedef struct {
305312
lr_t lr_common; /* common portion of log record */
306313
uint64_t lr_doid; /* obj id of directory */
307314
/* name of object to remove follows this */
315+
uint8_t lr_data[];
308316
} lr_remove_t;
309317

310318
typedef struct {
311319
lr_t lr_common; /* common portion of log record */
312320
uint64_t lr_doid; /* obj id of directory */
313321
uint64_t lr_link_obj; /* obj id of link */
314322
/* name of object to link follows this */
323+
uint8_t lr_data[];
315324
} lr_link_t;
316325

317326
typedef struct {
318327
lr_t lr_common; /* common portion of log record */
319328
uint64_t lr_sdoid; /* obj id of source directory */
320329
uint64_t lr_tdoid; /* obj id of target directory */
330+
} _lr_rename_t;
331+
332+
typedef struct {
333+
_lr_rename_t lr_rename; /* common rename portion */
321334
/* 2 strings: names of source and destination follow this */
335+
uint8_t lr_data[];
322336
} lr_rename_t;
323337

324338
typedef struct {
325-
lr_rename_t lr_rename; /* common rename portion */
326-
/* members related to the whiteout file (based on lr_create_t) */
339+
_lr_rename_t lr_rename; /* common rename portion */
340+
/* members related to the whiteout file (based on _lr_create_t) */
327341
uint64_t lr_wfoid; /* obj id of the new whiteout file */
328342
uint64_t lr_wmode; /* mode of object */
329343
uint64_t lr_wuid; /* uid of whiteout */
@@ -332,6 +346,7 @@ typedef struct {
332346
uint64_t lr_wcrtime[2]; /* creation time */
333347
uint64_t lr_wrdev; /* always makedev(0, 0) */
334348
/* 2 strings: names of source and destination follow this */
349+
uint8_t lr_data[];
335350
} lr_rename_whiteout_t;
336351

337352
typedef struct {
@@ -342,6 +357,7 @@ typedef struct {
342357
uint64_t lr_blkoff; /* no longer used */
343358
blkptr_t lr_blkptr; /* spa block pointer for replay */
344359
/* write data will follow for small writes */
360+
uint8_t lr_data[];
345361
} lr_write_t;
346362

347363
typedef struct {
@@ -362,20 +378,23 @@ typedef struct {
362378
uint64_t lr_atime[2]; /* access time */
363379
uint64_t lr_mtime[2]; /* modification time */
364380
/* optional attribute lr_attr_t may be here */
381+
uint8_t lr_data[];
365382
} lr_setattr_t;
366383

367384
typedef struct {
368385
lr_t lr_common; /* common portion of log record */
369386
uint64_t lr_foid; /* file object to change attributes */
370387
uint64_t lr_size;
371388
/* xattr name and value follows */
389+
uint8_t lr_data[];
372390
} lr_setsaxattr_t;
373391

374392
typedef struct {
375393
lr_t lr_common; /* common portion of log record */
376394
uint64_t lr_foid; /* obj id of file */
377395
uint64_t lr_aclcnt; /* number of acl entries */
378396
/* lr_aclcnt number of ace_t entries follow this */
397+
uint8_t lr_data[];
379398
} lr_acl_v0_t;
380399

381400
typedef struct {
@@ -387,6 +406,7 @@ typedef struct {
387406
uint64_t lr_acl_bytes; /* number of bytes in ACL */
388407
uint64_t lr_acl_flags; /* ACL flags */
389408
/* lr_acl_bytes number of variable sized ace's follows */
409+
uint8_t lr_data[];
390410
} lr_acl_t;
391411

392412
typedef struct {
@@ -396,8 +416,8 @@ typedef struct {
396416
uint64_t lr_length; /* length of the blocks to clone */
397417
uint64_t lr_blksz; /* file's block size */
398418
uint64_t lr_nbps; /* number of block pointers */
399-
blkptr_t lr_bps[];
400419
/* block pointers of the blocks to clone follows */
420+
blkptr_t lr_bps[];
401421
} lr_clone_range_t;
402422

403423
/*
@@ -448,7 +468,7 @@ typedef struct itx {
448468
uint64_t itx_oid; /* object id */
449469
uint64_t itx_gen; /* gen number for zfs_get_data */
450470
lr_t itx_lr; /* common part of log record */
451-
/* followed by type-specific part of lr_xx_t and its immediate data */
471+
uint8_t itx_lr_data[]; /* type-specific part of lr_xx_t */
452472
} itx_t;
453473

454474
/*

0 commit comments

Comments
 (0)