.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * vfsv0 quota IO operations on file |
---|
3 | 4 | */ |
---|
.. | .. |
---|
79 | 80 | return ret; |
---|
80 | 81 | } |
---|
81 | 82 | |
---|
| 83 | +static inline int do_check_range(struct super_block *sb, const char *val_name, |
---|
| 84 | + uint val, uint min_val, uint max_val) |
---|
| 85 | +{ |
---|
| 86 | + if (val < min_val || val > max_val) { |
---|
| 87 | + quota_error(sb, "Getting %s %u out of range %u-%u", |
---|
| 88 | + val_name, val, min_val, max_val); |
---|
| 89 | + return -EUCLEAN; |
---|
| 90 | + } |
---|
| 91 | + |
---|
| 92 | + return 0; |
---|
| 93 | +} |
---|
| 94 | + |
---|
| 95 | +static int check_dquot_block_header(struct qtree_mem_dqinfo *info, |
---|
| 96 | + struct qt_disk_dqdbheader *dh) |
---|
| 97 | +{ |
---|
| 98 | + int err = 0; |
---|
| 99 | + |
---|
| 100 | + err = do_check_range(info->dqi_sb, "dqdh_next_free", |
---|
| 101 | + le32_to_cpu(dh->dqdh_next_free), 0, |
---|
| 102 | + info->dqi_blocks - 1); |
---|
| 103 | + if (err) |
---|
| 104 | + return err; |
---|
| 105 | + err = do_check_range(info->dqi_sb, "dqdh_prev_free", |
---|
| 106 | + le32_to_cpu(dh->dqdh_prev_free), 0, |
---|
| 107 | + info->dqi_blocks - 1); |
---|
| 108 | + |
---|
| 109 | + return err; |
---|
| 110 | +} |
---|
| 111 | + |
---|
82 | 112 | /* Remove empty block from list and return it */ |
---|
83 | 113 | static int get_free_dqblk(struct qtree_mem_dqinfo *info) |
---|
84 | 114 | { |
---|
.. | .. |
---|
92 | 122 | blk = info->dqi_free_blk; |
---|
93 | 123 | ret = read_blk(info, blk, buf); |
---|
94 | 124 | if (ret < 0) |
---|
| 125 | + goto out_buf; |
---|
| 126 | + ret = check_dquot_block_header(info, dh); |
---|
| 127 | + if (ret) |
---|
95 | 128 | goto out_buf; |
---|
96 | 129 | info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free); |
---|
97 | 130 | } |
---|
.. | .. |
---|
239 | 272 | blk = info->dqi_free_entry; |
---|
240 | 273 | *err = read_blk(info, blk, buf); |
---|
241 | 274 | if (*err < 0) |
---|
| 275 | + goto out_buf; |
---|
| 276 | + *err = check_dquot_block_header(info, dh); |
---|
| 277 | + if (*err) |
---|
242 | 278 | goto out_buf; |
---|
243 | 279 | } else { |
---|
244 | 280 | blk = get_free_dqblk(info); |
---|
.. | .. |
---|
432 | 468 | goto out_buf; |
---|
433 | 469 | } |
---|
434 | 470 | dh = (struct qt_disk_dqdbheader *)buf; |
---|
| 471 | + ret = check_dquot_block_header(info, dh); |
---|
| 472 | + if (ret) |
---|
| 473 | + goto out_buf; |
---|
435 | 474 | le16_add_cpu(&dh->dqdh_entries, -1); |
---|
436 | 475 | if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */ |
---|
437 | 476 | ret = remove_free_dqentry(info, buf, blk); |
---|