Skip to content

Commit eed1eec

Browse files
committed
Fixed information leaks through reused caches
As a shortcut, littlefs never bother to zero any of the buffers is used. It didn't need to because it would always write out the entirety of the data it needed. Unfortunately, this, combined with the extra padding used to align buffers to the nearest prog size, would lead to uninitialized data getting written out to disk. This means unrelated file data could be written to different parts of storage, or worse, information leaked from the malloc calls could be written out to disk unnecessarily. found by rojer
1 parent 4a86370 commit eed1eec

File tree

1 file changed

+30
-13
lines changed

1 file changed

+30
-13
lines changed

lfs.c

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,19 @@ static int lfs_cache_crc(lfs_t *lfs, lfs_cache_t *rcache,
107107
return 0;
108108
}
109109

110+
static inline void lfs_cache_drop(lfs_t *lfs, lfs_cache_t *rcache) {
111+
// do not zero, cheaper if cache is readonly or only going to be
112+
// written with identical data (during relocates)
113+
(void)lfs;
114+
rcache->block = 0xffffffff;
115+
}
116+
117+
static inline void lfs_cache_zero(lfs_t *lfs, lfs_cache_t *pcache) {
118+
// zero to avoid information leak
119+
memset(pcache->buffer, 0xff, lfs->cfg->prog_size);
120+
pcache->block = 0xffffffff;
121+
}
122+
110123
static int lfs_cache_flush(lfs_t *lfs,
111124
lfs_cache_t *pcache, lfs_cache_t *rcache) {
112125
if (pcache->block != 0xffffffff) {
@@ -128,7 +141,7 @@ static int lfs_cache_flush(lfs_t *lfs,
128141
}
129142
}
130143

131-
pcache->block = 0xffffffff;
144+
lfs_cache_zero(lfs, pcache);
132145
}
133146

134147
return 0;
@@ -233,7 +246,7 @@ static int lfs_bd_erase(lfs_t *lfs, lfs_block_t block) {
233246
}
234247

235248
static int lfs_bd_sync(lfs_t *lfs) {
236-
lfs->rcache.block = 0xffffffff;
249+
lfs_cache_drop(lfs, &lfs->rcache);
237250

238251
int err = lfs_cache_flush(lfs, &lfs->pcache, NULL);
239252
if (err) {
@@ -592,7 +605,7 @@ static int lfs_dir_commit(lfs_t *lfs, lfs_dir_t *dir,
592605

593606
// drop caches and prepare to relocate block
594607
relocated = true;
595-
lfs->pcache.block = 0xffffffff;
608+
lfs_cache_drop(lfs, &lfs->pcache);
596609

597610
// can't relocate superblock, filesystem is now frozen
598611
if (lfs_paircmp(oldpair, (const lfs_block_t[2]){0, 1}) == 0) {
@@ -1217,7 +1230,7 @@ static int lfs_ctz_extend(lfs_t *lfs,
12171230
LFS_DEBUG("Bad block at %d", nblock);
12181231

12191232
// just clear cache and try a new block
1220-
pcache->block = 0xffffffff;
1233+
lfs_cache_drop(lfs, &lfs->pcache);
12211234
}
12221235
}
12231236

@@ -1322,7 +1335,6 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
13221335
}
13231336

13241337
// allocate buffer if needed
1325-
file->cache.block = 0xffffffff;
13261338
if (lfs->cfg->file_buffer) {
13271339
if (lfs->files) {
13281340
// already in use
@@ -1341,6 +1353,9 @@ int lfs_file_open(lfs_t *lfs, lfs_file_t *file,
13411353
}
13421354
}
13431355

1356+
// zero to avoid information leak
1357+
lfs_cache_zero(lfs, &file->cache);
1358+
13441359
// add to list of files
13451360
file->next = lfs->files;
13461361
lfs->files = file;
@@ -1409,7 +1424,7 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) {
14091424
memcpy(file->cache.buffer, lfs->pcache.buffer, lfs->cfg->prog_size);
14101425
file->cache.block = lfs->pcache.block;
14111426
file->cache.off = lfs->pcache.off;
1412-
lfs->pcache.block = 0xffffffff;
1427+
lfs_cache_zero(lfs, &lfs->pcache);
14131428

14141429
file->block = nblock;
14151430
return 0;
@@ -1418,7 +1433,7 @@ static int lfs_file_relocate(lfs_t *lfs, lfs_file_t *file) {
14181433
static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
14191434
if (file->flags & LFS_F_READING) {
14201435
// just drop read cache
1421-
file->cache.block = 0xffffffff;
1436+
lfs_cache_drop(lfs, &file->cache);
14221437
file->flags &= ~LFS_F_READING;
14231438
}
14241439

@@ -1433,7 +1448,7 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
14331448
.pos = file->pos,
14341449
.cache = lfs->rcache,
14351450
};
1436-
lfs->rcache.block = 0xffffffff;
1451+
lfs_cache_drop(lfs, &lfs->rcache);
14371452

14381453
while (file->pos < file->size) {
14391454
// copy over a byte at a time, leave it up to caching
@@ -1451,8 +1466,8 @@ static int lfs_file_flush(lfs_t *lfs, lfs_file_t *file) {
14511466

14521467
// keep our reference to the rcache in sync
14531468
if (lfs->rcache.block != 0xffffffff) {
1454-
orig.cache.block = 0xffffffff;
1455-
lfs->rcache.block = 0xffffffff;
1469+
lfs_cache_drop(lfs, &orig.cache);
1470+
lfs_cache_drop(lfs, &lfs->rcache);
14561471
}
14571472
}
14581473

@@ -1630,7 +1645,7 @@ lfs_ssize_t lfs_file_write(lfs_t *lfs, lfs_file_t *file,
16301645
}
16311646

16321647
// mark cache as dirty since we may have read data into it
1633-
file->cache.block = 0xffffffff;
1648+
lfs_cache_zero(lfs, &file->cache);
16341649
}
16351650

16361651
// extend file with new blocks
@@ -1981,7 +1996,6 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
19811996
lfs->cfg = cfg;
19821997

19831998
// setup read cache
1984-
lfs->rcache.block = 0xffffffff;
19851999
if (lfs->cfg->read_buffer) {
19862000
lfs->rcache.buffer = lfs->cfg->read_buffer;
19872001
} else {
@@ -1992,7 +2006,6 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
19922006
}
19932007

19942008
// setup program cache
1995-
lfs->pcache.block = 0xffffffff;
19962009
if (lfs->cfg->prog_buffer) {
19972010
lfs->pcache.buffer = lfs->cfg->prog_buffer;
19982011
} else {
@@ -2002,6 +2015,10 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
20022015
}
20032016
}
20042017

2018+
// zero to avoid information leaks
2019+
lfs_cache_zero(lfs, &lfs->rcache);
2020+
lfs_cache_zero(lfs, &lfs->pcache);
2021+
20052022
// setup lookahead, round down to nearest 32-bits
20062023
LFS_ASSERT(lfs->cfg->lookahead % 32 == 0);
20072024
LFS_ASSERT(lfs->cfg->lookahead > 0);

0 commit comments

Comments
 (0)