Skip to content

Commit fe5f56b

Browse files
committed
Fix high-severity bugs
Bug fixes: - bitmap.h: Return 0 instead of -EIO on sb_bread failure (type mismatch) Also restore bitmap and block count on allocation failure - inode.c: Fix buffer leak in simplefs_lookup() - release bh on error - inode.c: Initialize fi variable and use explicit indices in simplefs_set_file_into_dir() to prevent undefined behavior - inode.c: Add null termination after strncpy for filenames - inode.c: Add bounds validation for extent avail index in simplefs_create(), simplefs_link(), and simplefs_symlink() - inode.c: Add missing extent nr_files increment in link/symlink In addition, this commit adds Linux 6.15+ compatibility. - Update write_begin() signature (kiocb-based API) - Update write_end() signature and file reference access - Conditionally exclude writepage from aops (deprecated) - Update simplefs_mkdir() to return 'struct dentry *'
1 parent d7e0c9b commit fe5f56b

File tree

3 files changed

+158
-30
lines changed

3 files changed

+158
-30
lines changed

bitmap.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,10 @@ static inline uint32_t get_free_blocks(struct super_block *sb, uint32_t len)
5757
bh = sb_bread(sb, ret + i);
5858
if (!bh) {
5959
pr_err("get_free_blocks: sb_bread failed for block %d\n", ret + i);
60+
/* Restore all len blocks - bitmap was cleared atomically */
61+
bitmap_set(sbi->bfree_bitmap, ret, len);
6062
sbi->nr_free_blocks += len;
61-
return -EIO;
63+
return 0; /* Return 0 to indicate failure (0 is reserved) */
6264
}
6365
memset(bh->b_data, 0, SIMPLEFS_BLOCK_SIZE);
6466
mark_buffer_dirty(bh);

file.c

Lines changed: 99 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -113,20 +113,91 @@ static int simplefs_writepage(struct page *page, struct writeback_control *wbc)
113113
* the data into the page cache. This function checks if the write operation
114114
* can complete and allocates the necessary blocks through block_write_begin().
115115
*/
116-
#if SIMPLEFS_AT_LEAST(6, 12, 0)
116+
#if SIMPLEFS_AT_LEAST(6, 15, 0)
117+
static int simplefs_write_begin(const struct kiocb *iocb,
118+
struct address_space *mapping,
119+
loff_t pos,
120+
unsigned int len,
121+
struct folio **foliop,
122+
void **fsdata)
123+
{
124+
struct file *file = iocb->ki_filp;
125+
struct simplefs_sb_info *sbi = SIMPLEFS_SB(file->f_inode->i_sb);
126+
int err;
127+
uint32_t nr_allocs = 0;
128+
129+
if (pos + len > SIMPLEFS_MAX_FILESIZE)
130+
return -ENOSPC;
131+
132+
nr_allocs = max(pos + len, file->f_inode->i_size) / SIMPLEFS_BLOCK_SIZE;
133+
if (nr_allocs > file->f_inode->i_blocks - 1)
134+
nr_allocs -= file->f_inode->i_blocks - 1;
135+
else
136+
nr_allocs = 0;
137+
if (nr_allocs > sbi->nr_free_blocks)
138+
return -ENOSPC;
139+
140+
err = block_write_begin(mapping, pos, len, foliop, simplefs_file_get_block);
141+
if (err < 0)
142+
pr_err("newly allocated blocks reclaim not implemented yet\n");
143+
return err;
144+
}
145+
#elif SIMPLEFS_AT_LEAST(6, 12, 0)
117146
static int simplefs_write_begin(struct file *file,
118147
struct address_space *mapping,
119148
loff_t pos,
120149
unsigned int len,
121150
struct folio **foliop,
122151
void **fsdata)
152+
{
153+
struct simplefs_sb_info *sbi = SIMPLEFS_SB(file->f_inode->i_sb);
154+
int err;
155+
uint32_t nr_allocs = 0;
156+
157+
if (pos + len > SIMPLEFS_MAX_FILESIZE)
158+
return -ENOSPC;
159+
160+
nr_allocs = max(pos + len, file->f_inode->i_size) / SIMPLEFS_BLOCK_SIZE;
161+
if (nr_allocs > file->f_inode->i_blocks - 1)
162+
nr_allocs -= file->f_inode->i_blocks - 1;
163+
else
164+
nr_allocs = 0;
165+
if (nr_allocs > sbi->nr_free_blocks)
166+
return -ENOSPC;
167+
168+
err = block_write_begin(mapping, pos, len, foliop, simplefs_file_get_block);
169+
if (err < 0)
170+
pr_err("newly allocated blocks reclaim not implemented yet\n");
171+
return err;
172+
}
123173
#elif SIMPLEFS_AT_LEAST(5, 19, 0)
124174
static int simplefs_write_begin(struct file *file,
125175
struct address_space *mapping,
126176
loff_t pos,
127177
unsigned int len,
128178
struct page **pagep,
129179
void **fsdata)
180+
{
181+
struct simplefs_sb_info *sbi = SIMPLEFS_SB(file->f_inode->i_sb);
182+
int err;
183+
uint32_t nr_allocs = 0;
184+
185+
if (pos + len > SIMPLEFS_MAX_FILESIZE)
186+
return -ENOSPC;
187+
188+
nr_allocs = max(pos + len, file->f_inode->i_size) / SIMPLEFS_BLOCK_SIZE;
189+
if (nr_allocs > file->f_inode->i_blocks - 1)
190+
nr_allocs -= file->f_inode->i_blocks - 1;
191+
else
192+
nr_allocs = 0;
193+
if (nr_allocs > sbi->nr_free_blocks)
194+
return -ENOSPC;
195+
196+
err = block_write_begin(mapping, pos, len, pagep, simplefs_file_get_block);
197+
if (err < 0)
198+
pr_err("newly allocated blocks reclaim not implemented yet\n");
199+
return err;
200+
}
130201
#else
131202
static int simplefs_write_begin(struct file *file,
132203
struct address_space *mapping,
@@ -135,13 +206,11 @@ static int simplefs_write_begin(struct file *file,
135206
unsigned int flags,
136207
struct page **pagep,
137208
void **fsdata)
138-
#endif
139209
{
140210
struct simplefs_sb_info *sbi = SIMPLEFS_SB(file->f_inode->i_sb);
141211
int err;
142212
uint32_t nr_allocs = 0;
143213

144-
/* Check if the write can be completed (enough space?) */
145214
if (pos + len > SIMPLEFS_MAX_FILESIZE)
146215
return -ENOSPC;
147216

@@ -153,33 +222,38 @@ static int simplefs_write_begin(struct file *file,
153222
if (nr_allocs > sbi->nr_free_blocks)
154223
return -ENOSPC;
155224

156-
/* prepare the write */
157-
#if SIMPLEFS_AT_LEAST(6, 12, 0)
158-
err = block_write_begin(mapping, pos, len, foliop, simplefs_file_get_block);
159-
#elif SIMPLEFS_AT_LEAST(5, 19, 0)
160-
err = block_write_begin(mapping, pos, len, pagep, simplefs_file_get_block);
161-
#else
162225
err = block_write_begin(mapping, pos, len, flags, pagep,
163226
simplefs_file_get_block);
164-
#endif
165-
/* if this failed, reclaim newly allocated blocks */
166227
if (err < 0)
167228
pr_err("newly allocated blocks reclaim not implemented yet\n");
168229
return err;
169230
}
231+
#endif
170232

171233
/* Called by the VFS after writing data from a write() syscall to the page
172234
* cache. This function updates inode metadata and truncates the file if
173235
* necessary.
174236
*/
175-
#if SIMPLEFS_AT_LEAST(6, 12, 0)
237+
#if SIMPLEFS_AT_LEAST(6, 15, 0)
238+
static int simplefs_write_end(const struct kiocb *iocb,
239+
struct address_space *mapping,
240+
loff_t pos,
241+
unsigned int len,
242+
unsigned int copied,
243+
struct folio *foliop,
244+
void *fsdata)
245+
{
246+
struct inode *inode = iocb->ki_filp->f_inode;
247+
#elif SIMPLEFS_AT_LEAST(6, 12, 0)
176248
static int simplefs_write_end(struct file *file,
177249
struct address_space *mapping,
178250
loff_t pos,
179251
unsigned int len,
180252
unsigned int copied,
181253
struct folio *foliop,
182254
void *fsdata)
255+
{
256+
struct inode *inode = file->f_inode;
183257
#else
184258
static int simplefs_write_end(struct file *file,
185259
struct address_space *mapping,
@@ -188,9 +262,9 @@ static int simplefs_write_end(struct file *file,
188262
unsigned int copied,
189263
struct page *page,
190264
void *fsdata)
191-
#endif
192265
{
193266
struct inode *inode = file->f_inode;
267+
#endif
194268
struct simplefs_inode_info *ci = SIMPLEFS_INODE(inode);
195269
struct super_block *sb = inode->i_sb;
196270
#if SIMPLEFS_AT_LEAST(6, 6, 0)
@@ -199,7 +273,10 @@ static int simplefs_write_end(struct file *file,
199273
uint32_t nr_blocks_old;
200274

201275
/* Complete the write() */
202-
#if SIMPLEFS_AT_LEAST(6, 12, 0)
276+
#if SIMPLEFS_AT_LEAST(6, 15, 0)
277+
int ret =
278+
generic_write_end(iocb, mapping, pos, len, copied, foliop, fsdata);
279+
#elif SIMPLEFS_AT_LEAST(6, 12, 0)
203280
int ret =
204281
generic_write_end(file, mapping, pos, len, copied, foliop, fsdata);
205282
#else
@@ -242,9 +319,15 @@ static int simplefs_write_end(struct file *file,
242319
/* Read ei_block to remove unused blocks */
243320
bh_index = sb_bread(sb, ci->ei_block);
244321
if (!bh_index) {
322+
#if SIMPLEFS_AT_LEAST(6, 15, 0)
323+
pr_err("Failed to truncate '%s'. Lost %llu blocks\n",
324+
iocb->ki_filp->f_path.dentry->d_name.name,
325+
nr_blocks_old - inode->i_blocks);
326+
#else
245327
pr_err("Failed to truncate '%s'. Lost %llu blocks\n",
246328
file->f_path.dentry->d_name.name,
247329
nr_blocks_old - inode->i_blocks);
330+
#endif
248331
goto end;
249332
}
250333
index = (struct simplefs_file_ei_block *) bh_index->b_data;
@@ -486,7 +569,9 @@ const struct address_space_operations simplefs_aops = {
486569
#else
487570
.readpage = simplefs_readpage,
488571
#endif
572+
#if !SIMPLEFS_AT_LEAST(6, 15, 0)
489573
.writepage = simplefs_writepage,
574+
#endif
490575
.write_begin = simplefs_write_begin,
491576
.write_end = simplefs_write_end,
492577
};

inode.c

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,10 @@ static struct dentry *simplefs_lookup(struct inode *dir,
147147
/* Iterate blocks in extent */
148148
for (bi = 0; bi < eblock->extents[ei].ee_len; bi++) {
149149
bh2 = sb_bread(sb, eblock->extents[ei].ee_start + bi);
150-
if (!bh2)
150+
if (!bh2) {
151+
brelse(bh);
151152
return ERR_PTR(-EIO);
153+
}
152154

153155
dblock = (struct simplefs_dir_block *) bh2->b_data;
154156

@@ -375,22 +377,26 @@ static void simplefs_set_file_into_dir(struct simplefs_dir_block *dblock,
375377
uint32_t inode_no,
376378
const char *name)
377379
{
378-
int fi;
380+
int fi = 0;
379381
if (dblock->nr_files != 0 && dblock->files[0].inode != 0) {
380382
for (fi = 0; fi < SIMPLEFS_FILES_PER_BLOCK - 1; fi++) {
381383
if (dblock->files[fi].nr_blk != 1)
382384
break;
383385
}
384386
dblock->files[fi + 1].inode = inode_no;
385387
dblock->files[fi + 1].nr_blk = dblock->files[fi].nr_blk - 1;
386-
strncpy(dblock->files[fi + 1].filename, name, SIMPLEFS_FILENAME_LEN);
388+
strncpy(dblock->files[fi + 1].filename, name,
389+
SIMPLEFS_FILENAME_LEN - 1);
390+
dblock->files[fi + 1].filename[SIMPLEFS_FILENAME_LEN - 1] = '\0';
387391
dblock->files[fi].nr_blk = 1;
388392
} else if (dblock->nr_files == 0) {
389-
dblock->files[fi].inode = inode_no;
390-
strncpy(dblock->files[fi].filename, name, SIMPLEFS_FILENAME_LEN);
393+
dblock->files[0].inode = inode_no;
394+
strncpy(dblock->files[0].filename, name, SIMPLEFS_FILENAME_LEN - 1);
395+
dblock->files[0].filename[SIMPLEFS_FILENAME_LEN - 1] = '\0';
391396
} else {
392397
dblock->files[0].inode = inode_no;
393-
strncpy(dblock->files[fi].filename, name, SIMPLEFS_FILENAME_LEN);
398+
strncpy(dblock->files[0].filename, name, SIMPLEFS_FILENAME_LEN - 1);
399+
dblock->files[0].filename[SIMPLEFS_FILENAME_LEN - 1] = '\0';
394400
}
395401
dblock->nr_files++;
396402
}
@@ -475,6 +481,12 @@ static int simplefs_create(struct inode *dir,
475481
dir_nr_files = eblock->nr_files;
476482
avail = simplefs_get_available_ext_idx(&dir_nr_files, eblock);
477483

484+
/* Validate avail index is within bounds */
485+
if (avail >= SIMPLEFS_MAX_EXTENTS) {
486+
ret = -EMLINK;
487+
goto iput;
488+
}
489+
478490
/* if there is not any empty space, alloc new one */
479491
if (!dir_nr_files && !eblock->extents[avail].ee_start) {
480492
ret = simplefs_put_new_ext(sb, avail, eblock);
@@ -924,7 +936,16 @@ static int simplefs_rename(struct inode *old_dir,
924936
return ret;
925937
}
926938

927-
#if SIMPLEFS_AT_LEAST(6, 3, 0)
939+
#if SIMPLEFS_AT_LEAST(6, 15, 0)
940+
static struct dentry *simplefs_mkdir(struct mnt_idmap *id,
941+
struct inode *dir,
942+
struct dentry *dentry,
943+
umode_t mode)
944+
{
945+
int ret = simplefs_create(id, dir, dentry, mode | S_IFDIR, 0);
946+
return ret ? ERR_PTR(ret) : NULL;
947+
}
948+
#elif SIMPLEFS_AT_LEAST(6, 3, 0)
928949
static int simplefs_mkdir(struct mnt_idmap *id,
929950
struct inode *dir,
930951
struct dentry *dentry,
@@ -1003,6 +1024,12 @@ static int simplefs_link(struct dentry *old_dentry,
10031024
int dir_nr_files = eblock->nr_files;
10041025
avail = simplefs_get_available_ext_idx(&dir_nr_files, eblock);
10051026

1027+
/* Validate avail index is within bounds */
1028+
if (avail >= SIMPLEFS_MAX_EXTENTS) {
1029+
ret = -EMLINK;
1030+
goto end;
1031+
}
1032+
10061033
/* if there is not any empty space, alloc new one */
10071034
if (!dir_nr_files && !eblock->extents[avail].ee_start) {
10081035
ret = simplefs_put_new_ext(sb, avail, eblock);
@@ -1035,6 +1062,7 @@ static int simplefs_link(struct dentry *old_dentry,
10351062
/* write the file info into simplefs_dir_block */
10361063
simplefs_set_file_into_dir(dblock, old_inode->i_ino, dentry->d_name.name);
10371064

1065+
eblock->extents[avail].nr_files++;
10381066
eblock->nr_files++;
10391067
mark_buffer_dirty(bh2);
10401068
mark_buffer_dirty(bh);
@@ -1086,31 +1114,41 @@ static int simplefs_symlink(struct inode *dir,
10861114
uint32_t avail;
10871115

10881116
/* Check if symlink content is not too long */
1089-
if (l > sizeof(ci->i_data))
1090-
return -ENAMETOOLONG;
1117+
if (l > sizeof(ci->i_data)) {
1118+
ret = -ENAMETOOLONG;
1119+
goto iput;
1120+
}
10911121

10921122
/* fill directory data block */
10931123
bh = sb_bread(sb, ci_dir->ei_block);
1094-
if (!bh)
1095-
return -EIO;
1124+
if (!bh) {
1125+
ret = -EIO;
1126+
goto iput;
1127+
}
10961128
eblock = (struct simplefs_file_ei_block *) bh->b_data;
10971129

10981130
if (eblock->nr_files == SIMPLEFS_MAX_SUBFILES) {
10991131
ret = -EMLINK;
11001132
printk(KERN_INFO "directory is full");
1101-
goto end;
1133+
goto iput;
11021134
}
11031135

11041136
int dir_nr_files = eblock->nr_files;
11051137
avail = simplefs_get_available_ext_idx(&dir_nr_files, eblock);
11061138

1139+
/* Validate avail index is within bounds */
1140+
if (avail >= SIMPLEFS_MAX_EXTENTS) {
1141+
ret = -EMLINK;
1142+
goto iput;
1143+
}
1144+
11071145
/* if there is not any empty space, alloc new one */
11081146
if (!dir_nr_files && !eblock->extents[avail].ee_start) {
11091147
ret = simplefs_put_new_ext(sb, avail, eblock);
11101148
switch (ret) {
11111149
case -ENOSPC:
11121150
ret = -ENOSPC;
1113-
goto end;
1151+
goto iput;
11141152
case -EIO:
11151153
ret = -EIO;
11161154
goto put_block;
@@ -1136,6 +1174,7 @@ static int simplefs_symlink(struct inode *dir,
11361174
/* write the file info into simplefs_dir_block */
11371175
simplefs_set_file_into_dir(dblock, inode->i_ino, dentry->d_name.name);
11381176

1177+
eblock->extents[avail].nr_files++;
11391178
eblock->nr_files++;
11401179
mark_buffer_dirty(bh2);
11411180
mark_buffer_dirty(bh);
@@ -1155,8 +1194,10 @@ static int simplefs_symlink(struct inode *dir,
11551194
eblock->extents[ei].ee_len);
11561195
memset(&eblock->extents[ei], 0, sizeof(struct simplefs_extent));
11571196
}
1158-
1159-
end:
1197+
iput:
1198+
put_blocks(SIMPLEFS_SB(sb), ci->ei_block, 1);
1199+
put_inode(SIMPLEFS_SB(sb), inode->i_ino);
1200+
iput(inode);
11601201
brelse(bh);
11611202
return ret;
11621203
}

0 commit comments

Comments
 (0)