477 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * This file is part of UBIFS.4 *5 * Copyright (C) 2006-2008 Nokia Corporation.6 *7 * Authors: Artem Bityutskiy (Битюцкий Артём)8 * Adrian Hunter9 */10 11/* This file implements reading and writing the master node */12 13#include "ubifs.h"14 15/**16 * ubifs_compare_master_node - compare two UBIFS master nodes17 * @c: UBIFS file-system description object18 * @m1: the first node19 * @m2: the second node20 *21 * This function compares two UBIFS master nodes. Returns 0 if they are equal22 * and nonzero if not.23 */24int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2)25{26 int ret;27 int behind;28 int hmac_offs = offsetof(struct ubifs_mst_node, hmac);29 30 /*31 * Do not compare the common node header since the sequence number and32 * hence the CRC are different.33 */34 ret = memcmp(m1 + UBIFS_CH_SZ, m2 + UBIFS_CH_SZ,35 hmac_offs - UBIFS_CH_SZ);36 if (ret)37 return ret;38 39 /*40 * Do not compare the embedded HMAC as well which also must be different41 * due to the different common node header.42 */43 behind = hmac_offs + UBIFS_MAX_HMAC_LEN;44 45 if (UBIFS_MST_NODE_SZ > behind)46 return memcmp(m1 + behind, m2 + behind, UBIFS_MST_NODE_SZ - behind);47 48 return 0;49}50 51/* mst_node_check_hash - Check hash of a master node52 * @c: UBIFS file-system description object53 * @mst: The master node54 * @expected: The expected hash of the master node55 *56 * This checks the hash of a master node against a given expected hash.57 * Note that we have two master nodes on a UBIFS image which have different58 * sequence numbers and consequently different CRCs. To be able to match59 * both master nodes we exclude the common node header containing the sequence60 * number and CRC from the hash.61 *62 * Returns 0 if the hashes are equal, a negative error code otherwise.63 */64static int mst_node_check_hash(const struct ubifs_info *c,65 const struct ubifs_mst_node *mst,66 const u8 *expected)67{68 u8 calc[UBIFS_MAX_HASH_LEN];69 const void *node = mst;70 int ret;71 72 ret = crypto_shash_tfm_digest(c->hash_tfm, node + sizeof(struct ubifs_ch),73 UBIFS_MST_NODE_SZ - sizeof(struct ubifs_ch),74 calc);75 if (ret)76 return ret;77 78 if (ubifs_check_hash(c, expected, calc))79 return -EPERM;80 81 return 0;82}83 84/**85 * scan_for_master - search the valid master node.86 * @c: UBIFS file-system description object87 *88 * This function scans the master node LEBs and search for the latest master89 * node. Returns zero in case of success, %-EUCLEAN if there master area is90 * corrupted and requires recovery, and a negative error code in case of91 * failure.92 */93static int scan_for_master(struct ubifs_info *c)94{95 struct ubifs_scan_leb *sleb;96 struct ubifs_scan_node *snod;97 int lnum, offs = 0, nodes_cnt, err;98 99 lnum = UBIFS_MST_LNUM;100 101 sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);102 if (IS_ERR(sleb))103 return PTR_ERR(sleb);104 nodes_cnt = sleb->nodes_cnt;105 if (nodes_cnt > 0) {106 snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,107 list);108 if (snod->type != UBIFS_MST_NODE)109 goto out_dump;110 memcpy(c->mst_node, snod->node, snod->len);111 offs = snod->offs;112 }113 ubifs_scan_destroy(sleb);114 115 lnum += 1;116 117 sleb = ubifs_scan(c, lnum, 0, c->sbuf, 1);118 if (IS_ERR(sleb))119 return PTR_ERR(sleb);120 if (sleb->nodes_cnt != nodes_cnt)121 goto out;122 if (!sleb->nodes_cnt)123 goto out;124 snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node, list);125 if (snod->type != UBIFS_MST_NODE)126 goto out_dump;127 if (snod->offs != offs)128 goto out;129 if (ubifs_compare_master_node(c, c->mst_node, snod->node))130 goto out;131 132 c->mst_offs = offs;133 ubifs_scan_destroy(sleb);134 135 if (!ubifs_authenticated(c))136 return 0;137 138 if (ubifs_hmac_zero(c, c->mst_node->hmac)) {139 err = mst_node_check_hash(c, c->mst_node,140 c->sup_node->hash_mst);141 if (err)142 ubifs_err(c, "Failed to verify master node hash");143 } else {144 err = ubifs_node_verify_hmac(c, c->mst_node,145 sizeof(struct ubifs_mst_node),146 offsetof(struct ubifs_mst_node, hmac));147 if (err)148 ubifs_err(c, "Failed to verify master node HMAC");149 }150 151 if (err)152 return -EPERM;153 154 return 0;155 156out:157 ubifs_scan_destroy(sleb);158 return -EUCLEAN;159 160out_dump:161 ubifs_err(c, "unexpected node type %d master LEB %d:%d",162 snod->type, lnum, snod->offs);163 ubifs_scan_destroy(sleb);164 return -EINVAL;165}166 167/**168 * validate_master - validate master node.169 * @c: UBIFS file-system description object170 *171 * This function validates data which was read from master node. Returns zero172 * if the data is all right and %-EINVAL if not.173 */174static int validate_master(const struct ubifs_info *c)175{176 long long main_sz;177 int err;178 179 if (c->max_sqnum >= SQNUM_WATERMARK) {180 err = 1;181 goto out;182 }183 184 if (c->cmt_no >= c->max_sqnum) {185 err = 2;186 goto out;187 }188 189 if (c->highest_inum >= INUM_WATERMARK) {190 err = 3;191 goto out;192 }193 194 if (c->lhead_lnum < UBIFS_LOG_LNUM ||195 c->lhead_lnum >= UBIFS_LOG_LNUM + c->log_lebs ||196 c->lhead_offs < 0 || c->lhead_offs >= c->leb_size ||197 c->lhead_offs & (c->min_io_size - 1)) {198 err = 4;199 goto out;200 }201 202 if (c->zroot.lnum >= c->leb_cnt || c->zroot.lnum < c->main_first ||203 c->zroot.offs >= c->leb_size || c->zroot.offs & 7) {204 err = 5;205 goto out;206 }207 208 if (c->zroot.len < c->ranges[UBIFS_IDX_NODE].min_len ||209 c->zroot.len > c->ranges[UBIFS_IDX_NODE].max_len) {210 err = 6;211 goto out;212 }213 214 if (c->gc_lnum >= c->leb_cnt || c->gc_lnum < c->main_first) {215 err = 7;216 goto out;217 }218 219 if (c->ihead_lnum >= c->leb_cnt || c->ihead_lnum < c->main_first ||220 c->ihead_offs % c->min_io_size || c->ihead_offs < 0 ||221 c->ihead_offs > c->leb_size || c->ihead_offs & 7) {222 err = 8;223 goto out;224 }225 226 main_sz = (long long)c->main_lebs * c->leb_size;227 if (c->bi.old_idx_sz & 7 || c->bi.old_idx_sz >= main_sz) {228 err = 9;229 goto out;230 }231 232 if (c->lpt_lnum < c->lpt_first || c->lpt_lnum > c->lpt_last ||233 c->lpt_offs < 0 || c->lpt_offs + c->nnode_sz > c->leb_size) {234 err = 10;235 goto out;236 }237 238 if (c->nhead_lnum < c->lpt_first || c->nhead_lnum > c->lpt_last ||239 c->nhead_offs < 0 || c->nhead_offs % c->min_io_size ||240 c->nhead_offs > c->leb_size) {241 err = 11;242 goto out;243 }244 245 if (c->ltab_lnum < c->lpt_first || c->ltab_lnum > c->lpt_last ||246 c->ltab_offs < 0 ||247 c->ltab_offs + c->ltab_sz > c->leb_size) {248 err = 12;249 goto out;250 }251 252 if (c->big_lpt && (c->lsave_lnum < c->lpt_first ||253 c->lsave_lnum > c->lpt_last || c->lsave_offs < 0 ||254 c->lsave_offs + c->lsave_sz > c->leb_size)) {255 err = 13;256 goto out;257 }258 259 if (c->lscan_lnum < c->main_first || c->lscan_lnum >= c->leb_cnt) {260 err = 14;261 goto out;262 }263 264 if (c->lst.empty_lebs < 0 || c->lst.empty_lebs > c->main_lebs - 2) {265 err = 15;266 goto out;267 }268 269 if (c->lst.idx_lebs < 0 || c->lst.idx_lebs > c->main_lebs - 1) {270 err = 16;271 goto out;272 }273 274 if (c->lst.total_free < 0 || c->lst.total_free > main_sz ||275 c->lst.total_free & 7) {276 err = 17;277 goto out;278 }279 280 if (c->lst.total_dirty < 0 || (c->lst.total_dirty & 7)) {281 err = 18;282 goto out;283 }284 285 if (c->lst.total_used < 0 || (c->lst.total_used & 7)) {286 err = 19;287 goto out;288 }289 290 if (c->lst.total_free + c->lst.total_dirty +291 c->lst.total_used > main_sz) {292 err = 20;293 goto out;294 }295 296 if (c->lst.total_dead + c->lst.total_dark +297 c->lst.total_used + c->bi.old_idx_sz > main_sz) {298 err = 21;299 goto out;300 }301 302 if (c->lst.total_dead < 0 ||303 c->lst.total_dead > c->lst.total_free + c->lst.total_dirty ||304 c->lst.total_dead & 7) {305 err = 22;306 goto out;307 }308 309 if (c->lst.total_dark < 0 ||310 c->lst.total_dark > c->lst.total_free + c->lst.total_dirty ||311 c->lst.total_dark & 7) {312 err = 23;313 goto out;314 }315 316 return 0;317 318out:319 ubifs_err(c, "bad master node at offset %d error %d", c->mst_offs, err);320 ubifs_dump_node(c, c->mst_node, c->mst_node_alsz);321 return -EINVAL;322}323 324/**325 * ubifs_read_master - read master node.326 * @c: UBIFS file-system description object327 *328 * This function finds and reads the master node during file-system mount. If329 * the flash is empty, it creates default master node as well. Returns zero in330 * case of success and a negative error code in case of failure.331 */332int ubifs_read_master(struct ubifs_info *c)333{334 int err, old_leb_cnt;335 336 c->mst_node = kzalloc(c->mst_node_alsz, GFP_KERNEL);337 if (!c->mst_node)338 return -ENOMEM;339 340 err = scan_for_master(c);341 if (err) {342 if (err == -EUCLEAN)343 err = ubifs_recover_master_node(c);344 if (err)345 /*346 * Note, we do not free 'c->mst_node' here because the347 * unmount routine will take care of this.348 */349 return err;350 }351 352 /* Make sure that the recovery flag is clear */353 c->mst_node->flags &= cpu_to_le32(~UBIFS_MST_RCVRY);354 355 c->max_sqnum = le64_to_cpu(c->mst_node->ch.sqnum);356 c->highest_inum = le64_to_cpu(c->mst_node->highest_inum);357 c->cmt_no = le64_to_cpu(c->mst_node->cmt_no);358 c->zroot.lnum = le32_to_cpu(c->mst_node->root_lnum);359 c->zroot.offs = le32_to_cpu(c->mst_node->root_offs);360 c->zroot.len = le32_to_cpu(c->mst_node->root_len);361 c->lhead_lnum = le32_to_cpu(c->mst_node->log_lnum);362 c->gc_lnum = le32_to_cpu(c->mst_node->gc_lnum);363 c->ihead_lnum = le32_to_cpu(c->mst_node->ihead_lnum);364 c->ihead_offs = le32_to_cpu(c->mst_node->ihead_offs);365 c->bi.old_idx_sz = le64_to_cpu(c->mst_node->index_size);366 c->lpt_lnum = le32_to_cpu(c->mst_node->lpt_lnum);367 c->lpt_offs = le32_to_cpu(c->mst_node->lpt_offs);368 c->nhead_lnum = le32_to_cpu(c->mst_node->nhead_lnum);369 c->nhead_offs = le32_to_cpu(c->mst_node->nhead_offs);370 c->ltab_lnum = le32_to_cpu(c->mst_node->ltab_lnum);371 c->ltab_offs = le32_to_cpu(c->mst_node->ltab_offs);372 c->lsave_lnum = le32_to_cpu(c->mst_node->lsave_lnum);373 c->lsave_offs = le32_to_cpu(c->mst_node->lsave_offs);374 c->lscan_lnum = le32_to_cpu(c->mst_node->lscan_lnum);375 c->lst.empty_lebs = le32_to_cpu(c->mst_node->empty_lebs);376 c->lst.idx_lebs = le32_to_cpu(c->mst_node->idx_lebs);377 old_leb_cnt = le32_to_cpu(c->mst_node->leb_cnt);378 c->lst.total_free = le64_to_cpu(c->mst_node->total_free);379 c->lst.total_dirty = le64_to_cpu(c->mst_node->total_dirty);380 c->lst.total_used = le64_to_cpu(c->mst_node->total_used);381 c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead);382 c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark);383 384 ubifs_copy_hash(c, c->mst_node->hash_root_idx, c->zroot.hash);385 386 c->calc_idx_sz = c->bi.old_idx_sz;387 388 if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS))389 c->no_orphs = 1;390 391 if (old_leb_cnt != c->leb_cnt) {392 /* The file system has been resized */393 int growth = c->leb_cnt - old_leb_cnt;394 395 if (c->leb_cnt < old_leb_cnt ||396 c->leb_cnt < UBIFS_MIN_LEB_CNT) {397 ubifs_err(c, "bad leb_cnt on master node");398 ubifs_dump_node(c, c->mst_node, c->mst_node_alsz);399 return -EINVAL;400 }401 402 dbg_mnt("Auto resizing (master) from %d LEBs to %d LEBs",403 old_leb_cnt, c->leb_cnt);404 c->lst.empty_lebs += growth;405 c->lst.total_free += growth * (long long)c->leb_size;406 c->lst.total_dark += growth * (long long)c->dark_wm;407 408 /*409 * Reflect changes back onto the master node. N.B. the master410 * node gets written immediately whenever mounting (or411 * remounting) in read-write mode, so we do not need to write it412 * here.413 */414 c->mst_node->leb_cnt = cpu_to_le32(c->leb_cnt);415 c->mst_node->empty_lebs = cpu_to_le32(c->lst.empty_lebs);416 c->mst_node->total_free = cpu_to_le64(c->lst.total_free);417 c->mst_node->total_dark = cpu_to_le64(c->lst.total_dark);418 }419 420 err = validate_master(c);421 if (err)422 return err;423 424 err = dbg_old_index_check_init(c, &c->zroot);425 426 return err;427}428 429/**430 * ubifs_write_master - write master node.431 * @c: UBIFS file-system description object432 *433 * This function writes the master node. Returns zero in case of success and a434 * negative error code in case of failure. The master node is written twice to435 * enable recovery.436 */437int ubifs_write_master(struct ubifs_info *c)438{439 int err, lnum, offs, len;440 441 ubifs_assert(c, !c->ro_media && !c->ro_mount);442 if (c->ro_error)443 return -EROFS;444 445 lnum = UBIFS_MST_LNUM;446 offs = c->mst_offs + c->mst_node_alsz;447 len = UBIFS_MST_NODE_SZ;448 449 if (offs + UBIFS_MST_NODE_SZ > c->leb_size) {450 err = ubifs_leb_unmap(c, lnum);451 if (err)452 return err;453 offs = 0;454 }455 456 c->mst_offs = offs;457 c->mst_node->highest_inum = cpu_to_le64(c->highest_inum);458 459 ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx);460 err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs,461 offsetof(struct ubifs_mst_node, hmac));462 if (err)463 return err;464 465 lnum += 1;466 467 if (offs == 0) {468 err = ubifs_leb_unmap(c, lnum);469 if (err)470 return err;471 }472 err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs,473 offsetof(struct ubifs_mst_node, hmac));474 475 return err;476}477