| .. | .. |
|---|
| 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); |
|---|