Pull UBIFS updates from Richard Weinberger: - Full filesystem authentication feature, UBIFS is now able to have the whole filesystem structure authenticated plus user data encrypted and authenticated. - Minor cleanups * tag 'tags/upstream-4.20-rc1' of git://git.infradead.org/linux-ubifs: (26 commits) ubifs: Remove unneeded semicolon Documentation: ubifs: Add authentication whitepaper ubifs: Enable authentication support ubifs: Do not update inode size in-place in authenticated mode ubifs: Add hashes and HMACs to default filesystem ubifs: authentication: Authenticate super block node ubifs: Create hash for default LPT ubfis: authentication: Authenticate master node ubifs: authentication: Authenticate LPT ubifs: Authenticate replayed journal ubifs: Add auth nodes to garbage collector journal head ubifs: Add authentication nodes to journal ubifs: authentication: Add hashes to index nodes ubifs: Add hashes to the tree node cache ubifs: Create functions to embed a HMAC in a node ubifs: Add helper functions for authentication support ubifs: Add separate functions to init/crc a node ubifs: Format changes for authentication support ubifs: Store read superblock node ubifs: Drop write_node ...
Unified · Split
| @@ -0,0 +1,426 @@ | ||
| 1 | +% UBIFS Authentication | |
| 2 | +% sigma star gmbh | |
| 3 | +% 2018 | |
| 4 | + | |
| 5 | +# Introduction | |
| 6 | + | |
| 7 | +UBIFS utilizes the fscrypt framework to provide confidentiality for file | |
| 8 | +contents and file names. This prevents attacks where an attacker is able to | |
| 9 | +read contents of the filesystem on a single point in time. A classic example | |
| 10 | +is a lost smartphone where the attacker is unable to read personal data stored | |
| 11 | +on the device without the filesystem decryption key. | |
| 12 | + | |
| 13 | +At the current state, UBIFS encryption however does not prevent attacks where | |
| 14 | +the attacker is able to modify the filesystem contents and the user uses the | |
| 15 | +device afterwards. In such a scenario an attacker can modify filesystem | |
| 16 | +contents arbitrarily without the user noticing. One example is to modify a | |
| 17 | +binary to perform a malicious action when executed [DMC-CBC-ATTACK]. Since | |
| 18 | +most of the filesystem metadata of UBIFS is stored in plain, this makes it | |
| 19 | +fairly easy to swap files and replace their contents. | |
| 20 | + | |
| 21 | +Other full disk encryption systems like dm-crypt cover all filesystem metadata, | |
| 22 | +which makes such kinds of attacks more complicated, but not impossible. | |
| 23 | +Especially, if the attacker is given access to the device multiple points in | |
| 24 | +time. For dm-crypt and other filesystems that build upon the Linux block IO | |
| 25 | +layer, the dm-integrity or dm-verity subsystems [DM-INTEGRITY, DM-VERITY] | |
| 26 | +can be used to get full data authentication at the block layer. | |
| 27 | +These can also be combined with dm-crypt [CRYPTSETUP2]. | |
| 28 | + | |
| 29 | +This document describes an approach to get file contents _and_ full metadata | |
| 30 | +authentication for UBIFS. Since UBIFS uses fscrypt for file contents and file | |
| 31 | +name encryption, the authentication system could be tied into fscrypt such that | |
| 32 | +existing features like key derivation can be utilized. It should however also | |
| 33 | +be possible to use UBIFS authentication without using encryption. | |
| 34 | + | |
| 35 | + | |
| 36 | +## MTD, UBI & UBIFS | |
| 37 | + | |
| 38 | +On Linux, the MTD (Memory Technology Devices) subsystem provides a uniform | |
| 39 | +interface to access raw flash devices. One of the more prominent subsystems that | |
| 40 | +work on top of MTD is UBI (Unsorted Block Images). It provides volume management | |
| 41 | +for flash devices and is thus somewhat similar to LVM for block devices. In | |
| 42 | +addition, it deals with flash-specific wear-leveling and transparent I/O error | |
| 43 | +handling. UBI offers logical erase blocks (LEBs) to the layers on top of it | |
| 44 | +and maps them transparently to physical erase blocks (PEBs) on the flash. | |
| 45 | + | |
| 46 | +UBIFS is a filesystem for raw flash which operates on top of UBI. Thus, wear | |
| 47 | +leveling and some flash specifics are left to UBI, while UBIFS focuses on | |
| 48 | +scalability, performance and recoverability. | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + +------------+ +*******+ +-----------+ +-----+ | |
| 53 | + | | * UBIFS * | UBI-BLOCK | | ... | | |
| 54 | + | JFFS/JFFS2 | +*******+ +-----------+ +-----+ | |
| 55 | + | | +-----------------------------+ +-----------+ +-----+ | |
| 56 | + | | | UBI | | MTD-BLOCK | | ... | | |
| 57 | + +------------+ +-----------------------------+ +-----------+ +-----+ | |
| 58 | + +------------------------------------------------------------------+ | |
| 59 | + | MEMORY TECHNOLOGY DEVICES (MTD) | | |
| 60 | + +------------------------------------------------------------------+ | |
| 61 | + +-----------------------------+ +--------------------------+ +-----+ | |
| 62 | + | NAND DRIVERS | | NOR DRIVERS | | ... | | |
| 63 | + +-----------------------------+ +--------------------------+ +-----+ | |
| 64 | + | |
| 65 | + Figure 1: Linux kernel subsystems for dealing with raw flash | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | +Internally, UBIFS maintains multiple data structures which are persisted on | |
| 70 | +the flash: | |
| 71 | + | |
| 72 | +- *Index*: an on-flash B+ tree where the leaf nodes contain filesystem data | |
| 73 | +- *Journal*: an additional data structure to collect FS changes before updating | |
| 74 | + the on-flash index and reduce flash wear. | |
| 75 | +- *Tree Node Cache (TNC)*: an in-memory B+ tree that reflects the current FS | |
| 76 | + state to avoid frequent flash reads. It is basically the in-memory | |
| 77 | + representation of the index, but contains additional attributes. | |
| 78 | +- *LEB property tree (LPT)*: an on-flash B+ tree for free space accounting per | |
| 79 | + UBI LEB. | |
| 80 | + | |
| 81 | +In the remainder of this section we will cover the on-flash UBIFS data | |
| 82 | +structures in more detail. The TNC is of less importance here since it is never | |
| 83 | +persisted onto the flash directly. More details on UBIFS can also be found in | |
| 84 | +[UBIFS-WP]. | |
| 85 | + | |
| 86 | + | |
| 87 | +### UBIFS Index & Tree Node Cache | |
| 88 | + | |
| 89 | +Basic on-flash UBIFS entities are called *nodes*. UBIFS knows different types | |
| 90 | +of nodes. Eg. data nodes (`struct ubifs_data_node`) which store chunks of file | |
| 91 | +contents or inode nodes (`struct ubifs_ino_node`) which represent VFS inodes. | |
| 92 | +Almost all types of nodes share a common header (`ubifs_ch`) containing basic | |
| 93 | +information like node type, node length, a sequence number, etc. (see | |
| 94 | +`fs/ubifs/ubifs-media.h`in kernel source). Exceptions are entries of the LPT | |
| 95 | +and some less important node types like padding nodes which are used to pad | |
| 96 | +unusable content at the end of LEBs. | |
| 97 | + | |
| 98 | +To avoid re-writing the whole B+ tree on every single change, it is implemented | |
| 99 | +as *wandering tree*, where only the changed nodes are re-written and previous | |
| 100 | +versions of them are obsoleted without erasing them right away. As a result, | |
| 101 | +the index is not stored in a single place on the flash, but *wanders* around | |
| 102 | +and there are obsolete parts on the flash as long as the LEB containing them is | |
| 103 | +not reused by UBIFS. To find the most recent version of the index, UBIFS stores | |
| 104 | +a special node called *master node* into UBI LEB 1 which always points to the | |
| 105 | +most recent root node of the UBIFS index. For recoverability, the master node | |
| 106 | +is additionally duplicated to LEB 2. Mounting UBIFS is thus a simple read of | |
| 107 | +LEB 1 and 2 to get the current master node and from there get the location of | |
| 108 | +the most recent on-flash index. | |
| 109 | + | |
| 110 | +The TNC is the in-memory representation of the on-flash index. It contains some | |
| 111 | +additional runtime attributes per node which are not persisted. One of these is | |
| 112 | +a dirty-flag which marks nodes that have to be persisted the next time the | |
| 113 | +index is written onto the flash. The TNC acts as a write-back cache and all | |
| 114 | +modifications of the on-flash index are done through the TNC. Like other caches, | |
| 115 | +the TNC does not have to mirror the full index into memory, but reads parts of | |
| 116 | +it from flash whenever needed. A *commit* is the UBIFS operation of updating the | |
| 117 | +on-flash filesystem structures like the index. On every commit, the TNC nodes | |
| 118 | +marked as dirty are written to the flash to update the persisted index. | |
| 119 | + | |
| 120 | + | |
| 121 | +### Journal | |
| 122 | + | |
| 123 | +To avoid wearing out the flash, the index is only persisted (*commited*) when | |
| 124 | +certain conditions are met (eg. `fsync(2)`). The journal is used to record | |
| 125 | +any changes (in form of inode nodes, data nodes etc.) between commits | |
| 126 | +of the index. During mount, the journal is read from the flash and replayed | |
| 127 | +onto the TNC (which will be created on-demand from the on-flash index). | |
| 128 | + | |
| 129 | +UBIFS reserves a bunch of LEBs just for the journal called *log area*. The | |
| 130 | +amount of log area LEBs is configured on filesystem creation (using | |
| 131 | +`mkfs.ubifs`) and stored in the superblock node. The log area contains only | |
| 132 | +two types of nodes: *reference nodes* and *commit start nodes*. A commit start | |
| 133 | +node is written whenever an index commit is performed. Reference nodes are | |
| 134 | +written on every journal update. Each reference node points to the position of | |
| 135 | +other nodes (inode nodes, data nodes etc.) on the flash that are part of this | |
| 136 | +journal entry. These nodes are called *buds* and describe the actual filesystem | |
| 137 | +changes including their data. | |
| 138 | + | |
| 139 | +The log area is maintained as a ring. Whenever the journal is almost full, | |
| 140 | +a commit is initiated. This also writes a commit start node so that during | |
| 141 | +mount, UBIFS will seek for the most recent commit start node and just replay | |
| 142 | +every reference node after that. Every reference node before the commit start | |
| 143 | +node will be ignored as they are already part of the on-flash index. | |
| 144 | + | |
| 145 | +When writing a journal entry, UBIFS first ensures that enough space is | |
| 146 | +available to write the reference node and buds part of this entry. Then, the | |
| 147 | +reference node is written and afterwards the buds describing the file changes. | |
| 148 | +On replay, UBIFS will record every reference node and inspect the location of | |
| 149 | +the referenced LEBs to discover the buds. If these are corrupt or missing, | |
| 150 | +UBIFS will attempt to recover them by re-reading the LEB. This is however only | |
| 151 | +done for the last referenced LEB of the journal. Only this can become corrupt | |
| 152 | +because of a power cut. If the recovery fails, UBIFS will not mount. An error | |
| 153 | +for every other LEB will directly cause UBIFS to fail the mount operation. | |
| 154 | + | |
| 155 | + | |
| 156 | + | ---- LOG AREA ---- | ---------- MAIN AREA ------------ | | |
| 157 | + | |
| 158 | + -----+------+-----+--------+---- ------+-----+-----+--------------- | |
| 159 | + \ | | | | / / | | | \ | |
| 160 | + / CS | REF | REF | | \ \ DENT | INO | INO | / | |
| 161 | + \ | | | | / / | | | \ | |
| 162 | + ----+------+-----+--------+--- -------+-----+-----+---------------- | |
| 163 | + | | ^ ^ | |
| 164 | + | | | | | |
| 165 | + +------------------------+ | | |
| 166 | + | | | |
| 167 | + +-------------------------------+ | |
| 168 | + | |
| 169 | + | |
| 170 | + Figure 2: UBIFS flash layout of log area with commit start nodes | |
| 171 | + (CS) and reference nodes (REF) pointing to main area | |
| 172 | + containing their buds | |
| 173 | + | |
| 174 | + | |
| 175 | +### LEB Property Tree/Table | |
| 176 | + | |
| 177 | +The LEB property tree is used to store per-LEB information. This includes the | |
| 178 | +LEB type and amount of free and *dirty* (old, obsolete content) space [1] on | |
| 179 | +the LEB. The type is important, because UBIFS never mixes index nodes with data | |
| 180 | +nodes on a single LEB and thus each LEB has a specific purpose. This again is | |
| 181 | +useful for free space calculations. See [UBIFS-WP] for more details. | |
| 182 | + | |
| 183 | +The LEB property tree again is a B+ tree, but it is much smaller than the | |
| 184 | +index. Due to its smaller size it is always written as one chunk on every | |
| 185 | +commit. Thus, saving the LPT is an atomic operation. | |
| 186 | + | |
| 187 | + | |
| 188 | +[1] Since LEBs can only be appended and never overwritten, there is a | |
| 189 | +difference between free space ie. the remaining space left on the LEB to be | |
| 190 | +written to without erasing it and previously written content that is obsolete | |
| 191 | +but can't be overwritten without erasing the full LEB. | |
| 192 | + | |
| 193 | + | |
| 194 | +# UBIFS Authentication | |
| 195 | + | |
| 196 | +This chapter introduces UBIFS authentication which enables UBIFS to verify | |
| 197 | +the authenticity and integrity of metadata and file contents stored on flash. | |
| 198 | + | |
| 199 | + | |
| 200 | +## Threat Model | |
| 201 | + | |
| 202 | +UBIFS authentication enables detection of offline data modification. While it | |
| 203 | +does not prevent it, it enables (trusted) code to check the integrity and | |
| 204 | +authenticity of on-flash file contents and filesystem metadata. This covers | |
| 205 | +attacks where file contents are swapped. | |
| 206 | + | |
| 207 | +UBIFS authentication will not protect against rollback of full flash contents. | |
| 208 | +Ie. an attacker can still dump the flash and restore it at a later time without | |
| 209 | +detection. It will also not protect against partial rollback of individual | |
| 210 | +index commits. That means that an attacker is able to partially undo changes. | |
| 211 | +This is possible because UBIFS does not immediately overwrites obsolete | |
| 212 | +versions of the index tree or the journal, but instead marks them as obsolete | |
| 213 | +and garbage collection erases them at a later time. An attacker can use this by | |
| 214 | +erasing parts of the current tree and restoring old versions that are still on | |
| 215 | +the flash and have not yet been erased. This is possible, because every commit | |
| 216 | +will always write a new version of the index root node and the master node | |
| 217 | +without overwriting the previous version. This is further helped by the | |
| 218 | +wear-leveling operations of UBI which copies contents from one physical | |
| 219 | +eraseblock to another and does not atomically erase the first eraseblock. | |
| 220 | + | |
| 221 | +UBIFS authentication does not cover attacks where an attacker is able to | |
| 222 | +execute code on the device after the authentication key was provided. | |
| 223 | +Additional measures like secure boot and trusted boot have to be taken to | |
| 224 | +ensure that only trusted code is executed on a device. | |
| 225 | + | |
| 226 | + | |
| 227 | +## Authentication | |
| 228 | + | |
| 229 | +To be able to fully trust data read from flash, all UBIFS data structures | |
| 230 | +stored on flash are authenticated. That is: | |
| 231 | + | |
| 232 | +- The index which includes file contents, file metadata like extended | |
| 233 | + attributes, file length etc. | |
| 234 | +- The journal which also contains file contents and metadata by recording changes | |
| 235 | + to the filesystem | |
| 236 | +- The LPT which stores UBI LEB metadata which UBIFS uses for free space accounting | |
| 237 | + | |
| 238 | + | |
| 239 | +### Index Authentication | |
| 240 | + | |
| 241 | +Through UBIFS' concept of a wandering tree, it already takes care of only | |
| 242 | +updating and persisting changed parts from leaf node up to the root node | |
| 243 | +of the full B+ tree. This enables us to augment the index nodes of the tree | |
| 244 | +with a hash over each node's child nodes. As a result, the index basically also | |
| 245 | +a Merkle tree. Since the leaf nodes of the index contain the actual filesystem | |
| 246 | +data, the hashes of their parent index nodes thus cover all the file contents | |
| 247 | +and file metadata. When a file changes, the UBIFS index is updated accordingly | |
| 248 | +from the leaf nodes up to the root node including the master node. This process | |
| 249 | +can be hooked to recompute the hash only for each changed node at the same time. | |
| 250 | +Whenever a file is read, UBIFS can verify the hashes from each leaf node up to | |
| 251 | +the root node to ensure the node's integrity. | |
| 252 | + | |
| 253 | +To ensure the authenticity of the whole index, the UBIFS master node stores a | |
| 254 | +keyed hash (HMAC) over its own contents and a hash of the root node of the index | |
| 255 | +tree. As mentioned above, the master node is always written to the flash whenever | |
| 256 | +the index is persisted (ie. on index commit). | |
| 257 | + | |
| 258 | +Using this approach only UBIFS index nodes and the master node are changed to | |
| 259 | +include a hash. All other types of nodes will remain unchanged. This reduces | |
| 260 | +the storage overhead which is precious for users of UBIFS (ie. embedded | |
| 261 | +devices). | |
| 262 | + | |
| 263 | + | |
| 264 | + +---------------+ | |
| 265 | + | Master Node | | |
| 266 | + | (hash) | | |
| 267 | + +---------------+ | |
| 268 | + | | |
| 269 | + v | |
| 270 | + +-------------------+ | |
| 271 | + | Index Node #1 | | |
| 272 | + | | | |
| 273 | + | branch0 branchn | | |
| 274 | + | (hash) (hash) | | |
| 275 | + +-------------------+ | |
| 276 | + | ... | (fanout: 8) | |
| 277 | + | | | |
| 278 | + +-------+ +------+ | |
| 279 | + | | | |
| 280 | + v v | |
| 281 | + +-------------------+ +-------------------+ | |
| 282 | + | Index Node #2 | | Index Node #3 | | |
| 283 | + | | | | | |
| 284 | + | branch0 branchn | | branch0 branchn | | |
| 285 | + | (hash) (hash) | | (hash) (hash) | | |
| 286 | + +-------------------+ +-------------------+ | |
| 287 | + | ... | ... | | |
| 288 | + v v v | |
| 289 | + +-----------+ +----------+ +-----------+ | |
| 290 | + | Data Node | | INO Node | | DENT Node | | |
| 291 | + +-----------+ +----------+ +-----------+ | |
| 292 | + | |
| 293 | + | |
| 294 | + Figure 3: Coverage areas of index node hash and master node HMAC | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | +The most important part for robustness and power-cut safety is to atomically | |
| 299 | +persist the hash and file contents. Here the existing UBIFS logic for how | |
| 300 | +changed nodes are persisted is already designed for this purpose such that | |
| 301 | +UBIFS can safely recover if a power-cut occurs while persisting. Adding | |
| 302 | +hashes to index nodes does not change this since each hash will be persisted | |
| 303 | +atomically together with its respective node. | |
| 304 | + | |
| 305 | + | |
| 306 | +### Journal Authentication | |
| 307 | + | |
| 308 | +The journal is authenticated too. Since the journal is continuously written | |
| 309 | +it is necessary to also add authentication information frequently to the | |
| 310 | +journal so that in case of a powercut not too much data can't be authenticated. | |
| 311 | +This is done by creating a continuous hash beginning from the commit start node | |
| 312 | +over the previous reference nodes, the current reference node, and the bud | |
| 313 | +nodes. From time to time whenever it is suitable authentication nodes are added | |
| 314 | +between the bud nodes. This new node type contains a HMAC over the current state | |
| 315 | +of the hash chain. That way a journal can be authenticated up to the last | |
| 316 | +authentication node. The tail of the journal which may not have a authentication | |
| 317 | +node cannot be authenticated and is skipped during journal replay. | |
| 318 | + | |
| 319 | +We get this picture for journal authentication: | |
| 320 | + | |
| 321 | + ,,,,,,,, | |
| 322 | + ,......,........................................... | |
| 323 | + ,. CS , hash1.----. hash2.----. | |
| 324 | + ,. | , . |hmac . |hmac | |
| 325 | + ,. v , . v . v | |
| 326 | + ,.REF#0,-> bud -> bud -> bud.-> auth -> bud -> bud.-> auth ... | |
| 327 | + ,..|...,........................................... | |
| 328 | + , | , | |
| 329 | + , | ,,,,,,,,,,,,,,, | |
| 330 | + . | hash3,----. | |
| 331 | + , | , |hmac | |
| 332 | + , v , v | |
| 333 | + , REF#1 -> bud -> bud,-> auth ... | |
| 334 | + ,,,|,,,,,,,,,,,,,,,,,, | |
| 335 | + v | |
| 336 | + REF#2 -> ... | |
| 337 | + | | |
| 338 | + V | |
| 339 | + ... | |
| 340 | + | |
| 341 | +Since the hash also includes the reference nodes an attacker cannot reorder or | |
| 342 | +skip any journal heads for replay. An attacker can only remove bud nodes or | |
| 343 | +reference nodes from the end of the journal, effectively rewinding the | |
| 344 | +filesystem at maximum back to the last commit. | |
| 345 | + | |
| 346 | +The location of the log area is stored in the master node. Since the master | |
| 347 | +node is authenticated with a HMAC as described above, it is not possible to | |
| 348 | +tamper with that without detection. The size of the log area is specified when | |
| 349 | +the filesystem is created using `mkfs.ubifs` and stored in the superblock node. | |
| 350 | +To avoid tampering with this and other values stored there, a HMAC is added to | |
| 351 | +the superblock struct. The superblock node is stored in LEB 0 and is only | |
| 352 | +modified on feature flag or similar changes, but never on file changes. | |
| 353 | + | |
| 354 | + | |
| 355 | +### LPT Authentication | |
| 356 | + | |
| 357 | +The location of the LPT root node on the flash is stored in the UBIFS master | |
| 358 | +node. Since the LPT is written and read atomically on every commit, there is | |
| 359 | +no need to authenticate individual nodes of the tree. It suffices to | |
| 360 | +protect the integrity of the full LPT by a simple hash stored in the master | |
| 361 | +node. Since the master node itself is authenticated, the LPTs authenticity can | |
| 362 | +be verified by verifying the authenticity of the master node and comparing the | |
| 363 | +LTP hash stored there with the hash computed from the read on-flash LPT. | |
| 364 | + | |
| 365 | + | |
| 366 | +## Key Management | |
| 367 | + | |
| 368 | +For simplicity, UBIFS authentication uses a single key to compute the HMACs | |
| 369 | +of superblock, master, commit start and reference nodes. This key has to be | |
| 370 | +available on creation of the filesystem (`mkfs.ubifs`) to authenticate the | |
| 371 | +superblock node. Further, it has to be available on mount of the filesystem | |
| 372 | +to verify authenticated nodes and generate new HMACs for changes. | |
| 373 | + | |
| 374 | +UBIFS authentication is intended to operate side-by-side with UBIFS encryption | |
| 375 | +(fscrypt) to provide confidentiality and authenticity. Since UBIFS encryption | |
| 376 | +has a different approach of encryption policies per directory, there can be | |
| 377 | +multiple fscrypt master keys and there might be folders without encryption. | |
| 378 | +UBIFS authentication on the other hand has an all-or-nothing approach in the | |
| 379 | +sense that it either authenticates everything of the filesystem or nothing. | |
| 380 | +Because of this and because UBIFS authentication should also be usable without | |
| 381 | +encryption, it does not share the same master key with fscrypt, but manages | |
| 382 | +a dedicated authentication key. | |
| 383 | + | |
| 384 | +The API for providing the authentication key has yet to be defined, but the | |
| 385 | +key can eg. be provided by userspace through a keyring similar to the way it | |
| 386 | +is currently done in fscrypt. It should however be noted that the current | |
| 387 | +fscrypt approach has shown its flaws and the userspace API will eventually | |
| 388 | +change [FSCRYPT-POLICY2]. | |
| 389 | + | |
| 390 | +Nevertheless, it will be possible for a user to provide a single passphrase | |
| 391 | +or key in userspace that covers UBIFS authentication and encryption. This can | |
| 392 | +be solved by the corresponding userspace tools which derive a second key for | |
| 393 | +authentication in addition to the derived fscrypt master key used for | |
| 394 | +encryption. | |
| 395 | + | |
| 396 | +To be able to check if the proper key is available on mount, the UBIFS | |
| 397 | +superblock node will additionally store a hash of the authentication key. This | |
| 398 | +approach is similar to the approach proposed for fscrypt encryption policy v2 | |
| 399 | +[FSCRYPT-POLICY2]. | |
| 400 | + | |
| 401 | + | |
| 402 | +# Future Extensions | |
| 403 | + | |
| 404 | +In certain cases where a vendor wants to provide an authenticated filesystem | |
| 405 | +image to customers, it should be possible to do so without sharing the secret | |
| 406 | +UBIFS authentication key. Instead, in addition the each HMAC a digital | |
| 407 | +signature could be stored where the vendor shares the public key alongside the | |
| 408 | +filesystem image. In case this filesystem has to be modified afterwards, | |
| 409 | +UBIFS can exchange all digital signatures with HMACs on first mount similar | |
| 410 | +to the way the IMA/EVM subsystem deals with such situations. The HMAC key | |
| 411 | +will then have to be provided beforehand in the normal way. | |
| 412 | + | |
| 413 | + | |
| 414 | +# References | |
| 415 | + | |
| 416 | +[CRYPTSETUP2] http://www.saout.de/pipermail/dm-crypt/2017-November/005745.html | |
| 417 | + | |
| 418 | +[DMC-CBC-ATTACK] http://www.jakoblell.com/blog/2013/12/22/practical-malleability-attack-against-cbc-encrypted-luks-partitions/ | |
| 419 | + | |
| 420 | +[DM-INTEGRITY] https://www.kernel.org/doc/Documentation/device-mapper/dm-integrity.txt | |
| 421 | + | |
| 422 | +[DM-VERITY] https://www.kernel.org/doc/Documentation/device-mapper/verity.txt | |
| 423 | + | |
| 424 | +[FSCRYPT-POLICY2] https://www.spinics.net/lists/linux-ext4/msg58710.html | |
| 425 | + | |
| 426 | +[UBIFS-WP] http://www.linux-mtd.infradead.org/doc/ubifs_whitepaper.pdf | |
| @@ -91,6 +91,13 @@ chk_data_crc do not skip checking CRCs on data nodes · 90 unmodified lines | ||
| 91 | 91 | compr=none override default compressor and set it to "none" |
| 92 | 92 | compr=lzo override default compressor and set it to "lzo" |
| 93 | 93 | compr=zlib override default compressor and set it to "zlib" |
| 94 | +auth_key= specify the key used for authenticating the filesystem. | |
| 95 | + Passing this option makes authentication mandatory. | |
| 96 | + The passed key must be present in the kernel keyring | |
| 97 | + and must be of type 'logon' | |
| 98 | +auth_hash_name= The hash algorithm used for authentication. Used for | |
| 99 | + both hashing and for creating HMACs. Typical values | |
| 100 | + include "sha256" or "sha512" | |
| 94 | 101 | |
| 95 | 102 | |
| 96 | 103 | Quick usage instructions |
| @@ -1072,6 +1072,7 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai, · 1071 unmodified lines | ||
| 1072 | 1072 | * be a result of power cut during erasure. |
| 1073 | 1073 | */ |
| 1074 | 1074 | ai->maybe_bad_peb_count += 1; |
| 1075 | + /* fall through */ | |
| 1075 | 1076 | case UBI_IO_BAD_HDR: |
| 1076 | 1077 | /* |
| 1077 | 1078 | * If we're facing a bad VID header we have to drop *all* |
| @@ -1334,8 +1334,10 @@ static int bytes_str_to_int(const char *str) · 1333 unmodified lines | ||
| 1334 | 1334 | switch (*endp) { |
| 1335 | 1335 | case 'G': |
| 1336 | 1336 | result *= 1024; |
| 1337 | + /* fall through */ | |
| 1337 | 1338 | case 'M': |
| 1338 | 1339 | result *= 1024; |
| 1340 | + /* fall through */ | |
| 1339 | 1341 | case 'K': |
| 1340 | 1342 | result *= 1024; |
| 1341 | 1343 | if (endp[1] == 'i' && endp[2] == 'B') |
| @@ -7,6 +7,7 @@ config UBIFS_FS · 6 unmodified lines | ||
| 7 | 7 | select CRYPTO if UBIFS_FS_ZLIB |
| 8 | 8 | select CRYPTO_LZO if UBIFS_FS_LZO |
| 9 | 9 | select CRYPTO_DEFLATE if UBIFS_FS_ZLIB |
| 10 | + select CRYPTO_HASH_INFO | |
| 10 | 11 | depends on MTD_UBI |
| 11 | 12 | help |
| 12 | 13 | UBIFS is a file system for flash devices which works on top of UBI. |
| @@ -85,3 +86,13 @@ config UBIFS_FS_SECURITY · 72 unmodified lines | ||
| 85 | 86 | the extended attribute support in advance. |
| 86 | 87 | |
| 87 | 88 | If you are not using a security module, say N. |
| 89 | + | |
| 90 | +config UBIFS_FS_AUTHENTICATION | |
| 91 | + bool "UBIFS authentication support" | |
| 92 | + select CRYPTO_HMAC | |
| 93 | + help | |
| 94 | + Enable authentication support for UBIFS. This feature offers protection | |
| 95 | + against offline changes for both data and metadata of the filesystem. | |
| 96 | + If you say yes here you should also select a hashing algorithm such as | |
| 97 | + sha256, these are not selected automatically since there are many | |
| 98 | + different options. | |
| @@ -8,3 +8,4 @@ ubifs-y += recovery.o ioctl.o lpt_commit.o tnc_misc.o debug.o · 7 unmodified lines | ||
| 8 | 8 | ubifs-y += misc.o |
| 9 | 9 | ubifs-$(CONFIG_UBIFS_FS_ENCRYPTION) += crypto.o |
| 10 | 10 | ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o |
| 11 | +ubifs-$(CONFIG_UBIFS_FS_AUTHENTICATION) += auth.o | |
| @@ -0,0 +1,502 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * This file is part of UBIFS. | |
| 4 | + * | |
| 5 | + * Copyright (C) 2018 Pengutronix, Sascha Hauer <s.hauer@pengutronix.de> | |
| 6 | + */ | |
| 7 | + | |
| 8 | +/* | |
| 9 | + * This file implements various helper functions for UBIFS authentication support | |
| 10 | + */ | |
| 11 | + | |
| 12 | +#include <linux/crypto.h> | |
| 13 | +#include <crypto/hash.h> | |
| 14 | +#include <crypto/sha.h> | |
| 15 | +#include <crypto/algapi.h> | |
| 16 | +#include <keys/user-type.h> | |
| 17 | + | |
| 18 | +#include "ubifs.h" | |
| 19 | + | |
| 20 | +/** | |
| 21 | + * ubifs_node_calc_hash - calculate the hash of a UBIFS node | |
| 22 | + * @c: UBIFS file-system description object | |
| 23 | + * @node: the node to calculate a hash for | |
| 24 | + * @hash: the returned hash | |
| 25 | + * | |
| 26 | + * Returns 0 for success or a negative error code otherwise. | |
| 27 | + */ | |
| 28 | +int __ubifs_node_calc_hash(const struct ubifs_info *c, const void *node, | |
| 29 | + u8 *hash) | |
| 30 | +{ | |
| 31 | + const struct ubifs_ch *ch = node; | |
| 32 | + SHASH_DESC_ON_STACK(shash, c->hash_tfm); | |
| 33 | + int err; | |
| 34 | + | |
| 35 | + shash->tfm = c->hash_tfm; | |
| 36 | + shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | |
| 37 | + | |
| 38 | + err = crypto_shash_digest(shash, node, le32_to_cpu(ch->len), hash); | |
| 39 | + if (err < 0) | |
| 40 | + return err; | |
| 41 | + return 0; | |
| 42 | +} | |
| 43 | + | |
| 44 | +/** | |
| 45 | + * ubifs_hash_calc_hmac - calculate a HMAC from a hash | |
| 46 | + * @c: UBIFS file-system description object | |
| 47 | + * @hash: the node to calculate a HMAC for | |
| 48 | + * @hmac: the returned HMAC | |
| 49 | + * | |
| 50 | + * Returns 0 for success or a negative error code otherwise. | |
| 51 | + */ | |
| 52 | +static int ubifs_hash_calc_hmac(const struct ubifs_info *c, const u8 *hash, | |
| 53 | + u8 *hmac) | |
| 54 | +{ | |
| 55 | + SHASH_DESC_ON_STACK(shash, c->hmac_tfm); | |
| 56 | + int err; | |
| 57 | + | |
| 58 | + shash->tfm = c->hmac_tfm; | |
| 59 | + shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | |
| 60 | + | |
| 61 | + err = crypto_shash_digest(shash, hash, c->hash_len, hmac); | |
| 62 | + if (err < 0) | |
| 63 | + return err; | |
| 64 | + return 0; | |
| 65 | +} | |
| 66 | + | |
| 67 | +/** | |
| 68 | + * ubifs_prepare_auth_node - Prepare an authentication node | |
| 69 | + * @c: UBIFS file-system description object | |
| 70 | + * @node: the node to calculate a hash for | |
| 71 | + * @hash: input hash of previous nodes | |
| 72 | + * | |
| 73 | + * This function prepares an authentication node for writing onto flash. | |
| 74 | + * It creates a HMAC from the given input hash and writes it to the node. | |
| 75 | + * | |
| 76 | + * Returns 0 for success or a negative error code otherwise. | |
| 77 | + */ | |
| 78 | +int ubifs_prepare_auth_node(struct ubifs_info *c, void *node, | |
| 79 | + struct shash_desc *inhash) | |
| 80 | +{ | |
| 81 | + SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm); | |
| 82 | + struct ubifs_auth_node *auth = node; | |
| 83 | + u8 *hash; | |
| 84 | + int err; | |
| 85 | + | |
| 86 | + hash = kmalloc(crypto_shash_descsize(c->hash_tfm), GFP_NOFS); | |
| 87 | + if (!hash) | |
| 88 | + return -ENOMEM; | |
| 89 | + | |
| 90 | + hash_desc->tfm = c->hash_tfm; | |
| 91 | + hash_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | |
| 92 | + ubifs_shash_copy_state(c, inhash, hash_desc); | |
| 93 | + | |
| 94 | + err = crypto_shash_final(hash_desc, hash); | |
| 95 | + if (err) | |
| 96 | + goto out; | |
| 97 | + | |
| 98 | + err = ubifs_hash_calc_hmac(c, hash, auth->hmac); | |
| 99 | + if (err) | |
| 100 | + goto out; | |
| 101 | + | |
| 102 | + auth->ch.node_type = UBIFS_AUTH_NODE; | |
| 103 | + ubifs_prepare_node(c, auth, ubifs_auth_node_sz(c), 0); | |
| 104 | + | |
| 105 | + err = 0; | |
| 106 | +out: | |
| 107 | + kfree(hash); | |
| 108 | + | |
| 109 | + return err; | |
| 110 | +} | |
| 111 | + | |
| 112 | +static struct shash_desc *ubifs_get_desc(const struct ubifs_info *c, | |
| 113 | + struct crypto_shash *tfm) | |
| 114 | +{ | |
| 115 | + struct shash_desc *desc; | |
| 116 | + int err; | |
| 117 | + | |
| 118 | + if (!ubifs_authenticated(c)) | |
| 119 | + return NULL; | |
| 120 | + | |
| 121 | + desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL); | |
| 122 | + if (!desc) | |
| 123 | + return ERR_PTR(-ENOMEM); | |
| 124 | + | |
| 125 | + desc->tfm = tfm; | |
| 126 | + desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | |
| 127 | + | |
| 128 | + err = crypto_shash_init(desc); | |
| 129 | + if (err) { | |
| 130 | + kfree(desc); | |
| 131 | + return ERR_PTR(err); | |
| 132 | + } | |
| 133 | + | |
| 134 | + return desc; | |
| 135 | +} | |
| 136 | + | |
| 137 | +/** | |
| 138 | + * __ubifs_hash_get_desc - get a descriptor suitable for hashing a node | |
| 139 | + * @c: UBIFS file-system description object | |
| 140 | + * | |
| 141 | + * This function returns a descriptor suitable for hashing a node. Free after use | |
| 142 | + * with kfree. | |
| 143 | + */ | |
| 144 | +struct shash_desc *__ubifs_hash_get_desc(const struct ubifs_info *c) | |
| 145 | +{ | |
| 146 | + return ubifs_get_desc(c, c->hash_tfm); | |
| 147 | +} | |
| 148 | + | |
| 149 | +/** | |
| 150 | + * __ubifs_shash_final - finalize shash | |
| 151 | + * @c: UBIFS file-system description object | |
| 152 | + * @desc: the descriptor | |
| 153 | + * @out: the output hash | |
| 154 | + * | |
| 155 | + * Simple wrapper around crypto_shash_final(), safe to be called with | |
| 156 | + * disabled authentication. | |
| 157 | + */ | |
| 158 | +int __ubifs_shash_final(const struct ubifs_info *c, struct shash_desc *desc, | |
| 159 | + u8 *out) | |
| 160 | +{ | |
| 161 | + if (ubifs_authenticated(c)) | |
| 162 | + return crypto_shash_final(desc, out); | |
| 163 | + | |
| 164 | + return 0; | |
| 165 | +} | |
| 166 | + | |
| 167 | +/** | |
| 168 | + * ubifs_bad_hash - Report hash mismatches | |
| 169 | + * @c: UBIFS file-system description object | |
| 170 | + * @node: the node | |
| 171 | + * @hash: the expected hash | |
| 172 | + * @lnum: the LEB @node was read from | |
| 173 | + * @offs: offset in LEB @node was read from | |
| 174 | + * | |
| 175 | + * This function reports a hash mismatch when a node has a different hash than | |
| 176 | + * expected. | |
| 177 | + */ | |
| 178 | +void ubifs_bad_hash(const struct ubifs_info *c, const void *node, const u8 *hash, | |
| 179 | + int lnum, int offs) | |
| 180 | +{ | |
| 181 | + int len = min(c->hash_len, 20); | |
| 182 | + int cropped = len != c->hash_len; | |
| 183 | + const char *cont = cropped ? "..." : ""; | |
| 184 | + | |
| 185 | + u8 calc[UBIFS_HASH_ARR_SZ]; | |
| 186 | + | |
| 187 | + __ubifs_node_calc_hash(c, node, calc); | |
| 188 | + | |
| 189 | + ubifs_err(c, "hash mismatch on node at LEB %d:%d", lnum, offs); | |
| 190 | + ubifs_err(c, "hash expected: %*ph%s", len, hash, cont); | |
| 191 | + ubifs_err(c, "hash calculated: %*ph%s", len, calc, cont); | |
| 192 | +} | |
| 193 | + | |
| 194 | +/** | |
| 195 | + * __ubifs_node_check_hash - check the hash of a node against given hash | |
| 196 | + * @c: UBIFS file-system description object | |
| 197 | + * @node: the node | |
| 198 | + * @expected: the expected hash | |
| 199 | + * | |
| 200 | + * This function calculates a hash over a node and compares it to the given hash. | |
| 201 | + * Returns 0 if both hashes are equal or authentication is disabled, otherwise a | |
| 202 | + * negative error code is returned. | |
| 203 | + */ | |
| 204 | +int __ubifs_node_check_hash(const struct ubifs_info *c, const void *node, | |
| 205 | + const u8 *expected) | |
| 206 | +{ | |
| 207 | + u8 calc[UBIFS_HASH_ARR_SZ]; | |
| 208 | + int err; | |
| 209 | + | |
| 210 | + err = __ubifs_node_calc_hash(c, node, calc); | |
| 211 | + if (err) | |
| 212 | + return err; | |
| 213 | + | |
| 214 | + if (ubifs_check_hash(c, expected, calc)) | |
| 215 | + return -EPERM; | |
| 216 | + | |
| 217 | + return 0; | |
| 218 | +} | |
| 219 | + | |
| 220 | +/** | |
| 221 | + * ubifs_init_authentication - initialize UBIFS authentication support | |
| 222 | + * @c: UBIFS file-system description object | |
| 223 | + * | |
| 224 | + * This function returns 0 for success or a negative error code otherwise. | |
| 225 | + */ | |
| 226 | +int ubifs_init_authentication(struct ubifs_info *c) | |
| 227 | +{ | |
| 228 | + struct key *keyring_key; | |
| 229 | + const struct user_key_payload *ukp; | |
| 230 | + int err; | |
| 231 | + char hmac_name[CRYPTO_MAX_ALG_NAME]; | |
| 232 | + | |
| 233 | + if (!c->auth_hash_name) { | |
| 234 | + ubifs_err(c, "authentication hash name needed with authentication"); | |
| 235 | + return -EINVAL; | |
| 236 | + } | |
| 237 | + | |
| 238 | + c->auth_hash_algo = match_string(hash_algo_name, HASH_ALGO__LAST, | |
| 239 | + c->auth_hash_name); | |
| 240 | + if ((int)c->auth_hash_algo < 0) { | |
| 241 | + ubifs_err(c, "Unknown hash algo %s specified", | |
| 242 | + c->auth_hash_name); | |
| 243 | + return -EINVAL; | |
| 244 | + } | |
| 245 | + | |
| 246 | + snprintf(hmac_name, CRYPTO_MAX_ALG_NAME, "hmac(%s)", | |
| 247 | + c->auth_hash_name); | |
| 248 | + | |
| 249 | + keyring_key = request_key(&key_type_logon, c->auth_key_name, NULL); | |
| 250 | + | |
| 251 | + if (IS_ERR(keyring_key)) { | |
| 252 | + ubifs_err(c, "Failed to request key: %ld", | |
| 253 | + PTR_ERR(keyring_key)); | |
| 254 | + return PTR_ERR(keyring_key); | |
| 255 | + } | |
| 256 | + | |
| 257 | + down_read(&keyring_key->sem); | |
| 258 | + | |
| 259 | + if (keyring_key->type != &key_type_logon) { | |
| 260 | + ubifs_err(c, "key type must be logon"); | |
| 261 | + err = -ENOKEY; | |
| 262 | + goto out; | |
| 263 | + } | |
| 264 | + | |
| 265 | + ukp = user_key_payload_locked(keyring_key); | |
| 266 | + if (!ukp) { | |
| 267 | + /* key was revoked before we acquired its semaphore */ | |
| 268 | + err = -EKEYREVOKED; | |
| 269 | + goto out; | |
| 270 | + } | |
| 271 | + | |
| 272 | + c->hash_tfm = crypto_alloc_shash(c->auth_hash_name, 0, | |
| 273 | + CRYPTO_ALG_ASYNC); | |
| 274 | + if (IS_ERR(c->hash_tfm)) { | |
| 275 | + err = PTR_ERR(c->hash_tfm); | |
| 276 | + ubifs_err(c, "Can not allocate %s: %d", | |
| 277 | + c->auth_hash_name, err); | |
| 278 | + goto out; | |
| 279 | + } | |
| 280 | + | |
| 281 | + c->hash_len = crypto_shash_digestsize(c->hash_tfm); | |
| 282 | + if (c->hash_len > UBIFS_HASH_ARR_SZ) { | |
| 283 | + ubifs_err(c, "hash %s is bigger than maximum allowed hash size (%d > %d)", | |
| 284 | + c->auth_hash_name, c->hash_len, UBIFS_HASH_ARR_SZ); | |
| 285 | + err = -EINVAL; | |
| 286 | + goto out_free_hash; | |
| 287 | + } | |
| 288 | + | |
| 289 | + c->hmac_tfm = crypto_alloc_shash(hmac_name, 0, CRYPTO_ALG_ASYNC); | |
| 290 | + if (IS_ERR(c->hmac_tfm)) { | |
| 291 | + err = PTR_ERR(c->hmac_tfm); | |
| 292 | + ubifs_err(c, "Can not allocate %s: %d", hmac_name, err); | |
| 293 | + goto out_free_hash; | |
| 294 | + } | |
| 295 | + | |
| 296 | + c->hmac_desc_len = crypto_shash_digestsize(c->hmac_tfm); | |
| 297 | + if (c->hmac_desc_len > UBIFS_HMAC_ARR_SZ) { | |
| 298 | + ubifs_err(c, "hmac %s is bigger than maximum allowed hmac size (%d > %d)", | |
| 299 | + hmac_name, c->hmac_desc_len, UBIFS_HMAC_ARR_SZ); | |
| 300 | + err = -EINVAL; | |
| 301 | + goto out_free_hash; | |
| 302 | + } | |
| 303 | + | |
| 304 | + err = crypto_shash_setkey(c->hmac_tfm, ukp->data, ukp->datalen); | |
| 305 | + if (err) | |
| 306 | + goto out_free_hmac; | |
| 307 | + | |
| 308 | + c->authenticated = true; | |
| 309 | + | |
| 310 | + c->log_hash = ubifs_hash_get_desc(c); | |
| 311 | + if (IS_ERR(c->log_hash)) | |
| 312 | + goto out_free_hmac; | |
| 313 | + | |
| 314 | + err = 0; | |
| 315 | + | |
| 316 | +out_free_hmac: | |
| 317 | + if (err) | |
| 318 | + crypto_free_shash(c->hmac_tfm); | |
| 319 | +out_free_hash: | |
| 320 | + if (err) | |
| 321 | + crypto_free_shash(c->hash_tfm); | |
| 322 | +out: | |
| 323 | + up_read(&keyring_key->sem); | |
| 324 | + key_put(keyring_key); | |
| 325 | + | |
| 326 | + return err; | |
| 327 | +} | |
| 328 | + | |
| 329 | +/** | |
| 330 | + * __ubifs_exit_authentication - release resource | |
| 331 | + * @c: UBIFS file-system description object | |
| 332 | + * | |
| 333 | + * This function releases the authentication related resources. | |
| 334 | + */ | |
| 335 | +void __ubifs_exit_authentication(struct ubifs_info *c) | |
| 336 | +{ | |
| 337 | + if (!ubifs_authenticated(c)) | |
| 338 | + return; | |
| 339 | + | |
| 340 | + crypto_free_shash(c->hmac_tfm); | |
| 341 | + crypto_free_shash(c->hash_tfm); | |
| 342 | + kfree(c->log_hash); | |
| 343 | +} | |
| 344 | + | |
| 345 | +/** | |
| 346 | + * ubifs_node_calc_hmac - calculate the HMAC of a UBIFS node | |
| 347 | + * @c: UBIFS file-system description object | |
| 348 | + * @node: the node to insert a HMAC into. | |
| 349 | + * @len: the length of the node | |
| 350 | + * @ofs_hmac: the offset in the node where the HMAC is inserted | |
| 351 | + * @hmac: returned HMAC | |
| 352 | + * | |
| 353 | + * This function calculates a HMAC of a UBIFS node. The HMAC is expected to be | |
| 354 | + * embedded into the node, so this area is not covered by the HMAC. Also not | |
| 355 | + * covered is the UBIFS_NODE_MAGIC and the CRC of the node. | |
| 356 | + */ | |
| 357 | +static int ubifs_node_calc_hmac(const struct ubifs_info *c, const void *node, | |
| 358 | + int len, int ofs_hmac, void *hmac) | |
| 359 | +{ | |
| 360 | + SHASH_DESC_ON_STACK(shash, c->hmac_tfm); | |
| 361 | + int hmac_len = c->hmac_desc_len; | |
| 362 | + int err; | |
| 363 | + | |
| 364 | + ubifs_assert(c, ofs_hmac > 8); | |
| 365 | + ubifs_assert(c, ofs_hmac + hmac_len < len); | |
| 366 | + | |
| 367 | + shash->tfm = c->hmac_tfm; | |
| 368 | + shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | |
| 369 | + | |
| 370 | + err = crypto_shash_init(shash); | |
| 371 | + if (err) | |
| 372 | + return err; | |
| 373 | + | |
| 374 | + /* behind common node header CRC up to HMAC begin */ | |
| 375 | + err = crypto_shash_update(shash, node + 8, ofs_hmac - 8); | |
| 376 | + if (err < 0) | |
| 377 | + return err; | |
| 378 | + | |
| 379 | + /* behind HMAC, if any */ | |
| 380 | + if (len - ofs_hmac - hmac_len > 0) { | |
| 381 | + err = crypto_shash_update(shash, node + ofs_hmac + hmac_len, | |
| 382 | + len - ofs_hmac - hmac_len); | |
| 383 | + if (err < 0) | |
| 384 | + return err; | |
| 385 | + } | |
| 386 | + | |
| 387 | + return crypto_shash_final(shash, hmac); | |
| 388 | +} | |
| 389 | + | |
| 390 | +/** | |
| 391 | + * __ubifs_node_insert_hmac - insert a HMAC into a UBIFS node | |
| 392 | + * @c: UBIFS file-system description object | |
| 393 | + * @node: the node to insert a HMAC into. | |
| 394 | + * @len: the length of the node | |
| 395 | + * @ofs_hmac: the offset in the node where the HMAC is inserted | |
| 396 | + * | |
| 397 | + * This function inserts a HMAC at offset @ofs_hmac into the node given in | |
| 398 | + * @node. | |
| 399 | + * | |
| 400 | + * This function returns 0 for success or a negative error code otherwise. | |
| 401 | + */ | |
| 402 | +int __ubifs_node_insert_hmac(const struct ubifs_info *c, void *node, int len, | |
| 403 | + int ofs_hmac) | |
| 404 | +{ | |
| 405 | + return ubifs_node_calc_hmac(c, node, len, ofs_hmac, node + ofs_hmac); | |
| 406 | +} | |
| 407 | + | |
| 408 | +/** | |
| 409 | + * __ubifs_node_verify_hmac - verify the HMAC of UBIFS node | |
| 410 | + * @c: UBIFS file-system description object | |
| 411 | + * @node: the node to insert a HMAC into. | |
| 412 | + * @len: the length of the node | |
| 413 | + * @ofs_hmac: the offset in the node where the HMAC is inserted | |
| 414 | + * | |
| 415 | + * This function verifies the HMAC at offset @ofs_hmac of the node given in | |
| 416 | + * @node. Returns 0 if successful or a negative error code otherwise. | |
| 417 | + */ | |
| 418 | +int __ubifs_node_verify_hmac(const struct ubifs_info *c, const void *node, | |
| 419 | + int len, int ofs_hmac) | |
| 420 | +{ | |
| 421 | + int hmac_len = c->hmac_desc_len; | |
| 422 | + u8 *hmac; | |
| 423 | + int err; | |
| 424 | + | |
| 425 | + hmac = kmalloc(hmac_len, GFP_NOFS); | |
| 426 | + if (!hmac) | |
| 427 | + return -ENOMEM; | |
| 428 | + | |
| 429 | + err = ubifs_node_calc_hmac(c, node, len, ofs_hmac, hmac); | |
| 430 | + if (err) | |
| 431 | + return err; | |
| 432 | + | |
| 433 | + err = crypto_memneq(hmac, node + ofs_hmac, hmac_len); | |
| 434 | + | |
| 435 | + kfree(hmac); | |
| 436 | + | |
| 437 | + if (!err) | |
| 438 | + return 0; | |
| 439 | + | |
| 440 | + return -EPERM; | |
| 441 | +} | |
| 442 | + | |
| 443 | +int __ubifs_shash_copy_state(const struct ubifs_info *c, struct shash_desc *src, | |
| 444 | + struct shash_desc *target) | |
| 445 | +{ | |
| 446 | + u8 *state; | |
| 447 | + int err; | |
| 448 | + | |
| 449 | + state = kmalloc(crypto_shash_descsize(src->tfm), GFP_NOFS); | |
| 450 | + if (!state) | |
| 451 | + return -ENOMEM; | |
| 452 | + | |
| 453 | + err = crypto_shash_export(src, state); | |
| 454 | + if (err) | |
| 455 | + goto out; | |
| 456 | + | |
| 457 | + err = crypto_shash_import(target, state); | |
| 458 | + | |
| 459 | +out: | |
| 460 | + kfree(state); | |
| 461 | + | |
| 462 | + return err; | |
| 463 | +} | |
| 464 | + | |
| 465 | +/** | |
| 466 | + * ubifs_hmac_wkm - Create a HMAC of the well known message | |
| 467 | + * @c: UBIFS file-system description object | |
| 468 | + * @hmac: The HMAC of the well known message | |
| 469 | + * | |
| 470 | + * This function creates a HMAC of a well known message. This is used | |
| 471 | + * to check if the provided key is suitable to authenticate a UBIFS | |
| 472 | + * image. This is only a convenience to the user to provide a better | |
| 473 | + * error message when the wrong key is provided. | |
| 474 | + * | |
| 475 | + * This function returns 0 for success or a negative error code otherwise. | |
| 476 | + */ | |
| 477 | +int ubifs_hmac_wkm(struct ubifs_info *c, u8 *hmac) | |
| 478 | +{ | |
| 479 | + SHASH_DESC_ON_STACK(shash, c->hmac_tfm); | |
| 480 | + int err; | |
| 481 | + const char well_known_message[] = "UBIFS"; | |
| 482 | + | |
| 483 | + if (!ubifs_authenticated(c)) | |
| 484 | + return 0; | |
| 485 | + | |
| 486 | + shash->tfm = c->hmac_tfm; | |
| 487 | + shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | |
| 488 | + | |
| 489 | + err = crypto_shash_init(shash); | |
| 490 | + if (err) | |
| 491 | + return err; | |
| 492 | + | |
| 493 | + err = crypto_shash_update(shash, well_known_message, | |
| 494 | + sizeof(well_known_message) - 1); | |
| 495 | + if (err < 0) | |
| 496 | + return err; | |
| 497 | + | |
| 498 | + err = crypto_shash_final(shash, hmac); | |
| 499 | + if (err) | |
| 500 | + return err; | |
| 501 | + return 0; | |
| 502 | +} | |
| @@ -165,6 +165,8 @@ const char *dbg_ntype(int type) · 164 unmodified lines | ||
| 165 | 165 | return "commit start node"; |
| 166 | 166 | case UBIFS_ORPH_NODE: |
| 167 | 167 | return "orphan node"; |
| 168 | + case UBIFS_AUTH_NODE: | |
| 169 | + return "auth node"; | |
| 168 | 170 | default: |
| 169 | 171 | return "unknown node"; |
| 170 | 172 | } |
| @@ -542,6 +544,10 @@ void ubifs_dump_node(const struct ubifs_info *c, const void *node) · 371 unmodified lines | ||
| 542 | 544 | (unsigned long long)le64_to_cpu(orph->inos[i])); |
| 543 | 545 | break; |
| 544 | 546 | } |
| 547 | + case UBIFS_AUTH_NODE: | |
| 548 | + { | |
| 549 | + break; | |
| 550 | + } | |
| 545 | 551 | default: |
| 546 | 552 | pr_err("node type %d was not recognized\n", |
| 547 | 553 | (int)ch->node_type); |
| @@ -254,7 +254,8 @@ static int sort_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb, · 253 unmodified lines | ||
| 254 | 254 | snod->type == UBIFS_DATA_NODE || |
| 255 | 255 | snod->type == UBIFS_DENT_NODE || |
| 256 | 256 | snod->type == UBIFS_XENT_NODE || |
| 257 | − snod->type == UBIFS_TRUN_NODE); | |
| 257 | + snod->type == UBIFS_TRUN_NODE || | |
| 258 | + snod->type == UBIFS_AUTH_NODE); | |
| 258 | 259 | |
| 259 | 260 | if (snod->type != UBIFS_INO_NODE && |
| 260 | 261 | snod->type != UBIFS_DATA_NODE && |
| @@ -364,12 +365,13 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb) · 103 unmodified lines | ||
| 364 | 365 | |
| 365 | 366 | /* Write nodes to their new location. Use the first-fit strategy */ |
| 366 | 367 | while (1) { |
| 367 | − int avail; | |
| 368 | + int avail, moved = 0; | |
| 368 | 369 | struct ubifs_scan_node *snod, *tmp; |
| 369 | 370 | |
| 370 | 371 | /* Move data nodes */ |
| 371 | 372 | list_for_each_entry_safe(snod, tmp, &sleb->nodes, list) { |
| 372 | − avail = c->leb_size - wbuf->offs - wbuf->used; | |
| 373 | + avail = c->leb_size - wbuf->offs - wbuf->used - | |
| 374 | + ubifs_auth_node_sz(c); | |
| 373 | 375 | if (snod->len > avail) |
| 374 | 376 | /* |
| 375 | 377 | * Do not skip data nodes in order to optimize |
| @@ -377,14 +379,21 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb) · 1 unmodified line | ||
| 377 | 379 | */ |
| 378 | 380 | break; |
| 379 | 381 | |
| 382 | + err = ubifs_shash_update(c, c->jheads[GCHD].log_hash, | |
| 383 | + snod->node, snod->len); | |
| 384 | + if (err) | |
| 385 | + goto out; | |
| 386 | + | |
| 380 | 387 | err = move_node(c, sleb, snod, wbuf); |
| 381 | 388 | if (err) |
| 382 | 389 | goto out; |
| 390 | + moved = 1; | |
| 383 | 391 | } |
| 384 | 392 | |
| 385 | 393 | /* Move non-data nodes */ |
| 386 | 394 | list_for_each_entry_safe(snod, tmp, &nondata, list) { |
| 387 | − avail = c->leb_size - wbuf->offs - wbuf->used; | |
| 395 | + avail = c->leb_size - wbuf->offs - wbuf->used - | |
| 396 | + ubifs_auth_node_sz(c); | |
| 388 | 397 | if (avail < min) |
| 389 | 398 | break; |
| 390 | 399 | |
| @@ -402,9 +411,41 @@ static int move_nodes(struct ubifs_info *c, struct ubifs_scan_leb *sleb) · 11 unmodified lines | ||
| 402 | 411 | continue; |
| 403 | 412 | } |
| 404 | 413 | |
| 414 | + err = ubifs_shash_update(c, c->jheads[GCHD].log_hash, | |
| 415 | + snod->node, snod->len); | |
| 416 | + if (err) | |
| 417 | + goto out; | |
| 418 | + | |
| 405 | 419 | err = move_node(c, sleb, snod, wbuf); |
| 406 | 420 | if (err) |
| 407 | 421 | goto out; |
| 422 | + moved = 1; | |
| 423 | + } | |
| 424 | + | |
| 425 | + if (ubifs_authenticated(c) && moved) { | |
| 426 | + struct ubifs_auth_node *auth; | |
| 427 | + | |
| 428 | + auth = kmalloc(ubifs_auth_node_sz(c), GFP_NOFS); | |
| 429 | + if (!auth) { | |
| 430 | + err = -ENOMEM; | |
| 431 | + goto out; | |
| 432 | + } | |
| 433 | + | |
| 434 | + err = ubifs_prepare_auth_node(c, auth, | |
| 435 | + c->jheads[GCHD].log_hash); | |
| 436 | + if (err) { | |
| 437 | + kfree(auth); | |
| 438 | + goto out; | |
| 439 | + } | |
| 440 | + | |
| 441 | + err = ubifs_wbuf_write_nolock(wbuf, auth, | |
| 442 | + ubifs_auth_node_sz(c)); | |
| 443 | + if (err) { | |
| 444 | + kfree(auth); | |
| 445 | + goto out; | |
| 446 | + } | |
| 447 | + | |
| 448 | + ubifs_add_dirt(c, wbuf->lnum, ubifs_auth_node_sz(c)); | |
| 408 | 449 | } |
| 409 | 450 | |
| 410 | 451 | if (list_empty(&sleb->nodes) && list_empty(&nondata)) |
| @@ -365,20 +365,8 @@ static unsigned long long next_sqnum(struct ubifs_info *c) · 364 unmodified lines | ||
| 365 | 365 | return sqnum; |
| 366 | 366 | } |
| 367 | 367 | |
| 368 | −/** | |
| 369 | − * ubifs_prepare_node - prepare node to be written to flash. | |
| 370 | − * @c: UBIFS file-system description object | |
| 371 | − * @node: the node to pad | |
| 372 | − * @len: node length | |
| 373 | − * @pad: if the buffer has to be padded | |
| 374 | − * | |
| 375 | − * This function prepares node at @node to be written to the media - it | |
| 376 | − * calculates node CRC, fills the common header, and adds proper padding up to | |
| 377 | − * the next minimum I/O unit if @pad is not zero. | |
| 378 | − */ | |
| 379 | −void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad) | |
| 368 | +void ubifs_init_node(struct ubifs_info *c, void *node, int len, int pad) | |
| 380 | 369 | { |
| 381 | − uint32_t crc; | |
| 382 | 370 | struct ubifs_ch *ch = node; |
| 383 | 371 | unsigned long long sqnum = next_sqnum(c); |
| 384 | 372 | |
| @@ -389,8 +377,6 @@ void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad) · 4 unmodified lines | ||
| 389 | 377 | ch->group_type = UBIFS_NO_NODE_GROUP; |
| 390 | 378 | ch->sqnum = cpu_to_le64(sqnum); |
| 391 | 379 | ch->padding[0] = ch->padding[1] = 0; |
| 392 | − crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8); | |
| 393 | − ch->crc = cpu_to_le32(crc); | |
| 394 | 380 | |
| 395 | 381 | if (pad) { |
| 396 | 382 | len = ALIGN(len, 8); |
| @@ -399,6 +385,68 @@ void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad) · 2 unmodified lines | ||
| 399 | 385 | } |
| 400 | 386 | } |
| 401 | 387 | |
| 388 | +void ubifs_crc_node(struct ubifs_info *c, void *node, int len) | |
| 389 | +{ | |
| 390 | + struct ubifs_ch *ch = node; | |
| 391 | + uint32_t crc; | |
| 392 | + | |
| 393 | + crc = crc32(UBIFS_CRC32_INIT, node + 8, len - 8); | |
| 394 | + ch->crc = cpu_to_le32(crc); | |
| 395 | +} | |
| 396 | + | |
| 397 | +/** | |
| 398 | + * ubifs_prepare_node_hmac - prepare node to be written to flash. | |
| 399 | + * @c: UBIFS file-system description object | |
| 400 | + * @node: the node to pad | |
| 401 | + * @len: node length | |
| 402 | + * @hmac_offs: offset of the HMAC in the node | |
| 403 | + * @pad: if the buffer has to be padded | |
| 404 | + * | |
| 405 | + * This function prepares node at @node to be written to the media - it | |
| 406 | + * calculates node CRC, fills the common header, and adds proper padding up to | |
| 407 | + * the next minimum I/O unit if @pad is not zero. if @hmac_offs is positive then | |
| 408 | + * a HMAC is inserted into the node at the given offset. | |
| 409 | + * | |
| 410 | + * This function returns 0 for success or a negative error code otherwise. | |
| 411 | + */ | |
| 412 | +int ubifs_prepare_node_hmac(struct ubifs_info *c, void *node, int len, | |
| 413 | + int hmac_offs, int pad) | |
| 414 | +{ | |
| 415 | + int err; | |
| 416 | + | |
| 417 | + ubifs_init_node(c, node, len, pad); | |
| 418 | + | |
| 419 | + if (hmac_offs > 0) { | |
| 420 | + err = ubifs_node_insert_hmac(c, node, len, hmac_offs); | |
| 421 | + if (err) | |
| 422 | + return err; | |
| 423 | + } | |
| 424 | + | |
| 425 | + ubifs_crc_node(c, node, len); | |
| 426 | + | |
| 427 | + return 0; | |
| 428 | +} | |
| 429 | + | |
| 430 | +/** | |
| 431 | + * ubifs_prepare_node - prepare node to be written to flash. | |
| 432 | + * @c: UBIFS file-system description object | |
| 433 | + * @node: the node to pad | |
| 434 | + * @len: node length | |
| 435 | + * @pad: if the buffer has to be padded | |
| 436 | + * | |
| 437 | + * This function prepares node at @node to be written to the media - it | |
| 438 | + * calculates node CRC, fills the common header, and adds proper padding up to | |
| 439 | + * the next minimum I/O unit if @pad is not zero. | |
| 440 | + */ | |
| 441 | +void ubifs_prepare_node(struct ubifs_info *c, void *node, int len, int pad) | |
| 442 | +{ | |
| 443 | + /* | |
| 444 | + * Deliberately ignore return value since this function can only fail | |
| 445 | + * when a hmac offset is given. | |
| 446 | + */ | |
| 447 | + ubifs_prepare_node_hmac(c, node, len, 0, pad); | |
| 448 | +} | |
| 449 | + | |
| 402 | 450 | /** |
| 403 | 451 | * ubifs_prep_grp_node - prepare node of a group to be written to flash. |
| 404 | 452 | * @c: UBIFS file-system description object |
| @@ -849,12 +897,13 @@ out: · 444 unmodified lines | ||
| 849 | 897 | } |
| 850 | 898 | |
| 851 | 899 | /** |
| 852 | − * ubifs_write_node - write node to the media. | |
| 900 | + * ubifs_write_node_hmac - write node to the media. | |
| 853 | 901 | * @c: UBIFS file-system description object |
| 854 | 902 | * @buf: the node to write |
| 855 | 903 | * @len: node length |
| 856 | 904 | * @lnum: logical eraseblock number |
| 857 | 905 | * @offs: offset within the logical eraseblock |
| 906 | + * @hmac_offs: offset of the HMAC within the node | |
| 858 | 907 | * |
| 859 | 908 | * This function automatically fills node magic number, assigns sequence |
| 860 | 909 | * number, and calculates node CRC checksum. The length of the @buf buffer has |
| @@ -862,8 +911,8 @@ out: · 1 unmodified line | ||
| 862 | 911 | * appends padding node and padding bytes if needed. Returns zero in case of |
| 863 | 912 | * success and a negative error code in case of failure. |
| 864 | 913 | */ |
| 865 | −int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum, | |
| 866 | − int offs) | |
| 914 | +int ubifs_write_node_hmac(struct ubifs_info *c, void *buf, int len, int lnum, | |
| 915 | + int offs, int hmac_offs) | |
| 867 | 916 | { |
| 868 | 917 | int err, buf_len = ALIGN(len, c->min_io_size); |
| 869 | 918 | |
| @@ -878,7 +927,10 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum, · 8 unmodified lines | ||
| 878 | 927 | if (c->ro_error) |
| 879 | 928 | return -EROFS; |
| 880 | 929 | |
| 881 | − ubifs_prepare_node(c, buf, len, 1); | |
| 930 | + err = ubifs_prepare_node_hmac(c, buf, len, hmac_offs, 1); | |
| 931 | + if (err) | |
| 932 | + return err; | |
| 933 | + | |
| 882 | 934 | err = ubifs_leb_write(c, lnum, buf, offs, buf_len); |
| 883 | 935 | if (err) |
| 884 | 936 | ubifs_dump_node(c, buf); |
| @@ -886,6 +938,26 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum, · 1 unmodified line | ||
| 886 | 938 | return err; |
| 887 | 939 | } |
| 888 | 940 | |
| 941 | +/** | |
| 942 | + * ubifs_write_node - write node to the media. | |
| 943 | + * @c: UBIFS file-system description object | |
| 944 | + * @buf: the node to write | |
| 945 | + * @len: node length | |
| 946 | + * @lnum: logical eraseblock number | |
| 947 | + * @offs: offset within the logical eraseblock | |
| 948 | + * | |
| 949 | + * This function automatically fills node magic number, assigns sequence | |
| 950 | + * number, and calculates node CRC checksum. The length of the @buf buffer has | |
| 951 | + * to be aligned to the minimal I/O unit size. This function automatically | |
| 952 | + * appends padding node and padding bytes if needed. Returns zero in case of | |
| 953 | + * success and a negative error code in case of failure. | |
| 954 | + */ | |
| 955 | +int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum, | |
| 956 | + int offs) | |
| 957 | +{ | |
| 958 | + return ubifs_write_node_hmac(c, buf, len, lnum, offs, -1); | |
| 959 | +} | |
| 960 | + | |
| 889 | 961 | /** |
| 890 | 962 | * ubifs_read_node_wbuf - read node from the media or write-buffer. |
| 891 | 963 | * @wbuf: wbuf to check for un-written data |
| @@ -90,6 +90,12 @@ static inline void zero_trun_node_unused(struct ubifs_trun_node *trun) · 89 unmodified lines | ||
| 90 | 90 | memset(trun->padding, 0, 12); |
| 91 | 91 | } |
| 92 | 92 | |
| 93 | +static void ubifs_add_auth_dirt(struct ubifs_info *c, int lnum) | |
| 94 | +{ | |
| 95 | + if (ubifs_authenticated(c)) | |
| 96 | + ubifs_add_dirt(c, lnum, ubifs_auth_node_sz(c)); | |
| 97 | +} | |
| 98 | + | |
| 93 | 99 | /** |
| 94 | 100 | * reserve_space - reserve space in the journal. |
| 95 | 101 | * @c: UBIFS file-system description object |
| @@ -228,34 +234,33 @@ out_return: · 132 unmodified lines | ||
| 228 | 234 | return err; |
| 229 | 235 | } |
| 230 | 236 | |
| 231 | −/** | |
| 232 | − * write_node - write node to a journal head. | |
| 233 | − * @c: UBIFS file-system description object | |
| 234 | − * @jhead: journal head | |
| 235 | − * @node: node to write | |
| 236 | − * @len: node length | |
| 237 | − * @lnum: LEB number written is returned here | |
| 238 | − * @offs: offset written is returned here | |
| 239 | − * | |
| 240 | − * This function writes a node to reserved space of journal head @jhead. | |
| 241 | − * Returns zero in case of success and a negative error code in case of | |
| 242 | − * failure. | |
| 243 | − */ | |
| 244 | −static int write_node(struct ubifs_info *c, int jhead, void *node, int len, | |
| 245 | − int *lnum, int *offs) | |
| 237 | +static int ubifs_hash_nodes(struct ubifs_info *c, void *node, | |
| 238 | + int len, struct shash_desc *hash) | |
| 246 | 239 | { |
| 247 | − struct ubifs_wbuf *wbuf = &c->jheads[jhead].wbuf; | |
| 240 | + int auth_node_size = ubifs_auth_node_sz(c); | |
| 241 | + int err; | |
| 248 | 242 | |
| 249 | − ubifs_assert(c, jhead != GCHD); | |
| 243 | + while (1) { | |
| 244 | + const struct ubifs_ch *ch = node; | |
| 245 | + int nodelen = le32_to_cpu(ch->len); | |
| 250 | 246 | |
| 251 | − *lnum = c->jheads[jhead].wbuf.lnum; | |
| 252 | − *offs = c->jheads[jhead].wbuf.offs + c->jheads[jhead].wbuf.used; | |
| 247 | + ubifs_assert(c, len >= auth_node_size); | |
| 253 | 248 | |
| 254 | − dbg_jnl("jhead %s, LEB %d:%d, len %d", | |
| 255 | − dbg_jhead(jhead), *lnum, *offs, len); | |
| 256 | − ubifs_prepare_node(c, node, len, 0); | |
| 249 | + if (len == auth_node_size) | |
| 250 | + break; | |
| 251 | + | |
| 252 | + ubifs_assert(c, len > nodelen); | |
| 253 | + ubifs_assert(c, ch->magic == cpu_to_le32(UBIFS_NODE_MAGIC)); | |
| 257 | 254 | |
| 258 | − return ubifs_wbuf_write_nolock(wbuf, node, len); | |
| 255 | + err = ubifs_shash_update(c, hash, (void *)node, nodelen); | |
| 256 | + if (err) | |
| 257 | + return err; | |
| 258 | + | |
| 259 | + node += ALIGN(nodelen, 8); | |
| 260 | + len -= ALIGN(nodelen, 8); | |
| 261 | + } | |
| 262 | + | |
| 263 | + return ubifs_prepare_auth_node(c, node, hash); | |
| 259 | 264 | } |
| 260 | 265 | |
| 261 | 266 | /** |
| @@ -268,9 +273,9 @@ static int write_node(struct ubifs_info *c, int jhead, void *node, int len, · 6 unmodified lines | ||
| 268 | 273 | * @offs: offset written is returned here |
| 269 | 274 | * @sync: non-zero if the write-buffer has to by synchronized |
| 270 | 275 | * |
| 271 | − * This function is the same as 'write_node()' but it does not assume the | |
| 272 | − * buffer it is writing is a node, so it does not prepare it (which means | |
| 273 | − * initializing common header and calculating CRC). | |
| 276 | + * This function writes data to the reserved space of journal head @jhead. | |
| 277 | + * Returns zero in case of success and a negative error code in case of | |
| 278 | + * failure. | |
| 274 | 279 | */ |
| 275 | 280 | static int write_head(struct ubifs_info *c, int jhead, void *buf, int len, |
| 276 | 281 | int *lnum, int *offs, int sync) |
| @@ -285,6 +290,12 @@ static int write_head(struct ubifs_info *c, int jhead, void *buf, int len, · 8 unmodified lines | ||
| 285 | 290 | dbg_jnl("jhead %s, LEB %d:%d, len %d", |
| 286 | 291 | dbg_jhead(jhead), *lnum, *offs, len); |
| 287 | 292 | |
| 293 | + if (ubifs_authenticated(c)) { | |
| 294 | + err = ubifs_hash_nodes(c, buf, len, c->jheads[jhead].log_hash); | |
| 295 | + if (err) | |
| 296 | + return err; | |
| 297 | + } | |
| 298 | + | |
| 288 | 299 | err = ubifs_wbuf_write_nolock(wbuf, buf, len); |
| 289 | 300 | if (err) |
| 290 | 301 | return err; |
| @@ -548,6 +559,9 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, · 257 unmodified lines | ||
| 548 | 559 | struct ubifs_dent_node *dent; |
| 549 | 560 | struct ubifs_ino_node *ino; |
| 550 | 561 | union ubifs_key dent_key, ino_key; |
| 562 | + u8 hash_dent[UBIFS_HASH_ARR_SZ]; | |
| 563 | + u8 hash_ino[UBIFS_HASH_ARR_SZ]; | |
| 564 | + u8 hash_ino_host[UBIFS_HASH_ARR_SZ]; | |
| 551 | 565 | |
| 552 | 566 | ubifs_assert(c, mutex_is_locked(&host_ui->ui_mutex)); |
| 553 | 567 | |
| @@ -570,7 +584,10 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, · 16 unmodified lines | ||
| 570 | 584 | |
| 571 | 585 | len = aligned_dlen + aligned_ilen + UBIFS_INO_NODE_SZ; |
| 572 | 586 | /* Make sure to also account for extended attributes */ |
| 573 | − len += host_ui->data_len; | |
| 587 | + if (ubifs_authenticated(c)) | |
| 588 | + len += ALIGN(host_ui->data_len, 8) + ubifs_auth_node_sz(c); | |
| 589 | + else | |
| 590 | + len += host_ui->data_len; | |
| 574 | 591 | |
| 575 | 592 | dent = kzalloc(len, GFP_NOFS); |
| 576 | 593 | if (!dent) |
| @@ -602,11 +619,21 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, · 25 unmodified lines | ||
| 602 | 619 | |
| 603 | 620 | zero_dent_node_unused(dent); |
| 604 | 621 | ubifs_prep_grp_node(c, dent, dlen, 0); |
| 622 | + err = ubifs_node_calc_hash(c, dent, hash_dent); | |
| 623 | + if (err) | |
| 624 | + goto out_release; | |
| 605 | 625 | |
| 606 | 626 | ino = (void *)dent + aligned_dlen; |
| 607 | 627 | pack_inode(c, ino, inode, 0); |
| 628 | + err = ubifs_node_calc_hash(c, ino, hash_ino); | |
| 629 | + if (err) | |
| 630 | + goto out_release; | |
| 631 | + | |
| 608 | 632 | ino = (void *)ino + aligned_ilen; |
| 609 | 633 | pack_inode(c, ino, dir, 1); |
| 634 | + err = ubifs_node_calc_hash(c, ino, hash_ino_host); | |
| 635 | + if (err) | |
| 636 | + goto out_release; | |
| 610 | 637 | |
| 611 | 638 | if (last_reference) { |
| 612 | 639 | err = ubifs_add_orphan(c, inode->i_ino); |
| @@ -628,6 +655,7 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, · 15 unmodified lines | ||
| 628 | 655 | } |
| 629 | 656 | release_head(c, BASEHD); |
| 630 | 657 | kfree(dent); |
| 658 | + ubifs_add_auth_dirt(c, lnum); | |
| 631 | 659 | |
| 632 | 660 | if (deletion) { |
| 633 | 661 | if (nm->hash) |
| @@ -638,7 +666,8 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, · 4 unmodified lines | ||
| 638 | 666 | goto out_ro; |
| 639 | 667 | err = ubifs_add_dirt(c, lnum, dlen); |
| 640 | 668 | } else |
| 641 | − err = ubifs_tnc_add_nm(c, &dent_key, lnum, dent_offs, dlen, nm); | |
| 669 | + err = ubifs_tnc_add_nm(c, &dent_key, lnum, dent_offs, dlen, | |
| 670 | + hash_dent, nm); | |
| 642 | 671 | if (err) |
| 643 | 672 | goto out_ro; |
| 644 | 673 | |
| @@ -650,14 +679,14 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, · 5 unmodified lines | ||
| 650 | 679 | */ |
| 651 | 680 | ino_key_init(c, &ino_key, inode->i_ino); |
| 652 | 681 | ino_offs = dent_offs + aligned_dlen; |
| 653 | − err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, ilen); | |
| 682 | + err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, ilen, hash_ino); | |
| 654 | 683 | if (err) |
| 655 | 684 | goto out_ro; |
| 656 | 685 | |
| 657 | 686 | ino_key_init(c, &ino_key, dir->i_ino); |
| 658 | 687 | ino_offs += aligned_ilen; |
| 659 | 688 | err = ubifs_tnc_add(c, &ino_key, lnum, ino_offs, |
| 660 | − UBIFS_INO_NODE_SZ + host_ui->data_len); | |
| 689 | + UBIFS_INO_NODE_SZ + host_ui->data_len, hash_ino_host); | |
| 661 | 690 | if (err) |
| 662 | 691 | goto out_ro; |
| 663 | 692 | |
| @@ -706,10 +735,12 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, · 42 unmodified lines | ||
| 706 | 735 | const union ubifs_key *key, const void *buf, int len) |
| 707 | 736 | { |
| 708 | 737 | struct ubifs_data_node *data; |
| 709 | − int err, lnum, offs, compr_type, out_len, compr_len; | |
| 738 | + int err, lnum, offs, compr_type, out_len, compr_len, auth_len; | |
| 710 | 739 | int dlen = COMPRESSED_DATA_NODE_BUF_SZ, allocated = 1; |
| 740 | + int write_len; | |
| 711 | 741 | struct ubifs_inode *ui = ubifs_inode(inode); |
| 712 | 742 | bool encrypted = ubifs_crypt_is_encrypted(inode); |
| 743 | + u8 hash[UBIFS_HASH_ARR_SZ]; | |
| 713 | 744 | |
| 714 | 745 | dbg_jnlk(key, "ino %lu, blk %u, len %d, key ", |
| 715 | 746 | (unsigned long)key_inum(c, key), key_block(c, key), len); |
| @@ -718,7 +749,9 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, · 2 unmodified lines | ||
| 718 | 749 | if (encrypted) |
| 719 | 750 | dlen += UBIFS_CIPHER_BLOCK_SIZE; |
| 720 | 751 | |
| 721 | − data = kmalloc(dlen, GFP_NOFS | __GFP_NOWARN); | |
| 752 | + auth_len = ubifs_auth_node_sz(c); | |
| 753 | + | |
| 754 | + data = kmalloc(dlen + auth_len, GFP_NOFS | __GFP_NOWARN); | |
| 722 | 755 | if (!data) { |
| 723 | 756 | /* |
| 724 | 757 | * Fall-back to the write reserve buffer. Note, we might be |
| @@ -757,20 +790,33 @@ int ubifs_jnl_write_data(struct ubifs_info *c, const struct inode *inode, · 32 unmodified lines | ||
| 757 | 790 | } |
| 758 | 791 | |
| 759 | 792 | dlen = UBIFS_DATA_NODE_SZ + out_len; |
| 793 | + if (ubifs_authenticated(c)) | |
| 794 | + write_len = ALIGN(dlen, 8) + auth_len; | |
| 795 | + else | |
| 796 | + write_len = dlen; | |
| 797 | + | |
| 760 | 798 | data->compr_type = cpu_to_le16(compr_type); |
| 761 | 799 | |
| 762 | 800 | /* Make reservation before allocating sequence numbers */ |
| 763 | − err = make_reservation(c, DATAHD, dlen); | |
| 801 | + err = make_reservation(c, DATAHD, write_len); | |
| 764 | 802 | if (err) |
| 765 | 803 | goto out_free; |
| 766 | 804 | |
| 767 | − err = write_node(c, DATAHD, data, dlen, &lnum, &offs); | |
| 805 | + ubifs_prepare_node(c, data, dlen, 0); | |
| 806 | + err = write_head(c, DATAHD, data, write_len, &lnum, &offs, 0); | |
| 807 | + if (err) | |
| 808 | + goto out_release; | |
| 809 | + | |
| 810 | + err = ubifs_node_calc_hash(c, data, hash); | |
| 768 | 811 | if (err) |
| 769 | 812 | goto out_release; |
| 813 | + | |
| 770 | 814 | ubifs_wbuf_add_ino_nolock(&c->jheads[DATAHD].wbuf, key_inum(c, key)); |
| 771 | 815 | release_head(c, DATAHD); |
| 772 | 816 | |
| 773 | − err = ubifs_tnc_add(c, key, lnum, offs, dlen); | |
| 817 | + ubifs_add_auth_dirt(c, lnum); | |
| 818 | + | |
| 819 | + err = ubifs_tnc_add(c, key, lnum, offs, dlen, hash); | |
| 774 | 820 | if (err) |
| 775 | 821 | goto out_ro; |
| 776 | 822 | |
| @@ -808,7 +854,9 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) · 31 unmodified lines | ||
| 808 | 854 | int err, lnum, offs; |
| 809 | 855 | struct ubifs_ino_node *ino; |
| 810 | 856 | struct ubifs_inode *ui = ubifs_inode(inode); |
| 811 | − int sync = 0, len = UBIFS_INO_NODE_SZ, last_reference = !inode->i_nlink; | |
| 857 | + int sync = 0, write_len, ilen = UBIFS_INO_NODE_SZ; | |
| 858 | + int last_reference = !inode->i_nlink; | |
| 859 | + u8 hash[UBIFS_HASH_ARR_SZ]; | |
| 812 | 860 | |
| 813 | 861 | dbg_jnl("ino %lu, nlink %u", inode->i_ino, inode->i_nlink); |
| 814 | 862 | |
| @@ -817,20 +865,30 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) · 2 unmodified lines | ||
| 817 | 865 | * need to synchronize the write-buffer either. |
| 818 | 866 | */ |
| 819 | 867 | if (!last_reference) { |
| 820 | − len += ui->data_len; | |
| 868 | + ilen += ui->data_len; | |
| 821 | 869 | sync = IS_SYNC(inode); |
| 822 | 870 | } |
| 823 | − ino = kmalloc(len, GFP_NOFS); | |
| 871 | + | |
| 872 | + if (ubifs_authenticated(c)) | |
| 873 | + write_len = ALIGN(ilen, 8) + ubifs_auth_node_sz(c); | |
| 874 | + else | |
| 875 | + write_len = ilen; | |
| 876 | + | |
| 877 | + ino = kmalloc(write_len, GFP_NOFS); | |
| 824 | 878 | if (!ino) |
| 825 | 879 | return -ENOMEM; |
| 826 | 880 | |
| 827 | 881 | /* Make reservation before allocating sequence numbers */ |
| 828 | − err = make_reservation(c, BASEHD, len); | |
| 882 | + err = make_reservation(c, BASEHD, write_len); | |
| 829 | 883 | if (err) |
| 830 | 884 | goto out_free; |
| 831 | 885 | |
| 832 | 886 | pack_inode(c, ino, inode, 1); |
| 833 | − err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync); | |
| 887 | + err = ubifs_node_calc_hash(c, ino, hash); | |
| 888 | + if (err) | |
| 889 | + goto out_release; | |
| 890 | + | |
| 891 | + err = write_head(c, BASEHD, ino, write_len, &lnum, &offs, sync); | |
| 834 | 892 | if (err) |
| 835 | 893 | goto out_release; |
| 836 | 894 | if (!sync) |
| @@ -838,17 +896,19 @@ int ubifs_jnl_write_inode(struct ubifs_info *c, const struct inode *inode) · 1 unmodified line | ||
| 838 | 896 | inode->i_ino); |
| 839 | 897 | release_head(c, BASEHD); |
| 840 | 898 | |
| 899 | + ubifs_add_auth_dirt(c, lnum); | |
| 900 | + | |
| 841 | 901 | if (last_reference) { |
| 842 | 902 | err = ubifs_tnc_remove_ino(c, inode->i_ino); |
| 843 | 903 | if (err) |
| 844 | 904 | goto out_ro; |
| 845 | 905 | ubifs_delete_orphan(c, inode->i_ino); |
| 846 | − err = ubifs_add_dirt(c, lnum, len); | |
| 906 | + err = ubifs_add_dirt(c, lnum, ilen); | |
| 847 | 907 | } else { |
| 848 | 908 | union ubifs_key key; |
| 849 | 909 | |
| 850 | 910 | ino_key_init(c, &key, inode->i_ino); |
| 851 | − err = ubifs_tnc_add(c, &key, lnum, offs, len); | |
| 911 | + err = ubifs_tnc_add(c, &key, lnum, offs, ilen, hash); | |
| 852 | 912 | } |
| 853 | 913 | if (err) |
| 854 | 914 | goto out_ro; |
| @@ -958,6 +1018,10 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, · 103 unmodified lines | ||
| 958 | 1018 | int aligned_dlen1, aligned_dlen2; |
| 959 | 1019 | int twoparents = (fst_dir != snd_dir); |
| 960 | 1020 | void *p; |
| 1021 | + u8 hash_dent1[UBIFS_HASH_ARR_SZ]; | |
| 1022 | + u8 hash_dent2[UBIFS_HASH_ARR_SZ]; | |
| 1023 | + u8 hash_p1[UBIFS_HASH_ARR_SZ]; | |
| 1024 | + u8 hash_p2[UBIFS_HASH_ARR_SZ]; | |
| 961 | 1025 | |
| 962 | 1026 | ubifs_assert(c, ubifs_inode(fst_dir)->data_len == 0); |
| 963 | 1027 | ubifs_assert(c, ubifs_inode(snd_dir)->data_len == 0); |
| @@ -973,6 +1037,8 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, · 9 unmodified lines | ||
| 973 | 1037 | if (twoparents) |
| 974 | 1038 | len += plen; |
| 975 | 1039 | |
| 1040 | + len += ubifs_auth_node_sz(c); | |
| 1041 | + | |
| 976 | 1042 | dent1 = kzalloc(len, GFP_NOFS); |
| 977 | 1043 | if (!dent1) |
| 978 | 1044 | return -ENOMEM; |
| @@ -993,6 +1059,9 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, · 14 unmodified lines | ||
| 993 | 1059 | set_dent_cookie(c, dent1); |
| 994 | 1060 | zero_dent_node_unused(dent1); |
| 995 | 1061 | ubifs_prep_grp_node(c, dent1, dlen1, 0); |
| 1062 | + err = ubifs_node_calc_hash(c, dent1, hash_dent1); | |
| 1063 | + if (err) | |
| 1064 | + goto out_release; | |
| 996 | 1065 | |
| 997 | 1066 | /* Make new dent for 2nd entry */ |
| 998 | 1067 | dent2 = (void *)dent1 + aligned_dlen1; |
| @@ -1006,14 +1075,26 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, · 7 unmodified lines | ||
| 1006 | 1075 | set_dent_cookie(c, dent2); |
| 1007 | 1076 | zero_dent_node_unused(dent2); |
| 1008 | 1077 | ubifs_prep_grp_node(c, dent2, dlen2, 0); |
| 1078 | + err = ubifs_node_calc_hash(c, dent2, hash_dent2); | |
| 1079 | + if (err) | |
| 1080 | + goto out_release; | |
| 1009 | 1081 | |
| 1010 | 1082 | p = (void *)dent2 + aligned_dlen2; |
| 1011 | − if (!twoparents) | |
| 1083 | + if (!twoparents) { | |
| 1012 | 1084 | pack_inode(c, p, fst_dir, 1); |
| 1013 | − else { | |
| 1085 | + err = ubifs_node_calc_hash(c, p, hash_p1); | |
| 1086 | + if (err) | |
| 1087 | + goto out_release; | |
| 1088 | + } else { | |
| 1014 | 1089 | pack_inode(c, p, fst_dir, 0); |
| 1090 | + err = ubifs_node_calc_hash(c, p, hash_p1); | |
| 1091 | + if (err) | |
| 1092 | + goto out_release; | |
| 1015 | 1093 | p += ALIGN(plen, 8); |
| 1016 | 1094 | pack_inode(c, p, snd_dir, 1); |
| 1095 | + err = ubifs_node_calc_hash(c, p, hash_p2); | |
| 1096 | + if (err) | |
| 1097 | + goto out_release; | |
| 1017 | 1098 | } |
| 1018 | 1099 | |
| 1019 | 1100 | err = write_head(c, BASEHD, dent1, len, &lnum, &offs, sync); |
| @@ -1027,28 +1108,30 @@ int ubifs_jnl_xrename(struct ubifs_info *c, const struct inode *fst_dir, · 7 unmodified lines | ||
| 1027 | 1108 | } |
| 1028 | 1109 | release_head(c, BASEHD); |
| 1029 | 1110 | |
| 1111 | + ubifs_add_auth_dirt(c, lnum); | |
| 1112 | + | |
| 1030 | 1113 | dent_key_init(c, &key, snd_dir->i_ino, snd_nm); |
| 1031 | − err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, snd_nm); | |
| 1114 | + err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, hash_dent1, snd_nm); | |
| 1032 | 1115 | if (err) |
| 1033 | 1116 | goto out_ro; |
| 1034 | 1117 | |
| 1035 | 1118 | offs += aligned_dlen1; |
| 1036 | 1119 | dent_key_init(c, &key, fst_dir->i_ino, fst_nm); |
| 1037 | − err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, fst_nm); | |
| 1120 | + err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, hash_dent2, fst_nm); | |
| 1038 | 1121 | if (err) |
| 1039 | 1122 | goto out_ro; |
| 1040 | 1123 | |
| 1041 | 1124 | offs += aligned_dlen2; |
| 1042 | 1125 | |
| 1043 | 1126 | ino_key_init(c, &key, fst_dir->i_ino); |
| 1044 | − err = ubifs_tnc_add(c, &key, lnum, offs, plen); | |
| 1127 | + err = ubifs_tnc_add(c, &key, lnum, offs, plen, hash_p1); | |
| 1045 | 1128 | if (err) |
| 1046 | 1129 | goto out_ro; |
| 1047 | 1130 | |
| 1048 | 1131 | if (twoparents) { |
| 1049 | 1132 | offs += ALIGN(plen, 8); |
| 1050 | 1133 | ino_key_init(c, &key, snd_dir->i_ino); |
| 1051 | − err = ubifs_tnc_add(c, &key, lnum, offs, plen); | |
| 1134 | + err = ubifs_tnc_add(c, &key, lnum, offs, plen, hash_p2); | |
| 1052 | 1135 | if (err) |
| 1053 | 1136 | goto out_ro; |
| 1054 | 1137 | } |
| @@ -1101,6 +1184,11 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, · 46 unmodified lines | ||
| 1101 | 1184 | int last_reference = !!(new_inode && new_inode->i_nlink == 0); |
| 1102 | 1185 | int move = (old_dir != new_dir); |
| 1103 | 1186 | struct ubifs_inode *uninitialized_var(new_ui); |
| 1187 | + u8 hash_old_dir[UBIFS_HASH_ARR_SZ]; | |
| 1188 | + u8 hash_new_dir[UBIFS_HASH_ARR_SZ]; | |
| 1189 | + u8 hash_new_inode[UBIFS_HASH_ARR_SZ]; | |
| 1190 | + u8 hash_dent1[UBIFS_HASH_ARR_SZ]; | |
| 1191 | + u8 hash_dent2[UBIFS_HASH_ARR_SZ]; | |
| 1104 | 1192 | |
| 1105 | 1193 | ubifs_assert(c, ubifs_inode(old_dir)->data_len == 0); |
| 1106 | 1194 | ubifs_assert(c, ubifs_inode(new_dir)->data_len == 0); |
| @@ -1123,6 +1211,9 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, · 16 unmodified lines | ||
| 1123 | 1211 | len = aligned_dlen1 + aligned_dlen2 + ALIGN(ilen, 8) + ALIGN(plen, 8); |
| 1124 | 1212 | if (move) |
| 1125 | 1213 | len += plen; |
| 1214 | + | |
| 1215 | + len += ubifs_auth_node_sz(c); | |
| 1216 | + | |
| 1126 | 1217 | dent = kzalloc(len, GFP_NOFS); |
| 1127 | 1218 | if (!dent) |
| 1128 | 1219 | return -ENOMEM; |
| @@ -1143,6 +1234,9 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, · 14 unmodified lines | ||
| 1143 | 1234 | set_dent_cookie(c, dent); |
| 1144 | 1235 | zero_dent_node_unused(dent); |
| 1145 | 1236 | ubifs_prep_grp_node(c, dent, dlen1, 0); |
| 1237 | + err = ubifs_node_calc_hash(c, dent, hash_dent1); | |
| 1238 | + if (err) | |
| 1239 | + goto out_release; | |
| 1146 | 1240 | |
| 1147 | 1241 | dent2 = (void *)dent + aligned_dlen1; |
| 1148 | 1242 | dent2->ch.node_type = UBIFS_DENT_NODE; |
| @@ -1162,19 +1256,36 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, · 13 unmodified lines | ||
| 1162 | 1256 | set_dent_cookie(c, dent2); |
| 1163 | 1257 | zero_dent_node_unused(dent2); |
| 1164 | 1258 | ubifs_prep_grp_node(c, dent2, dlen2, 0); |
| 1259 | + err = ubifs_node_calc_hash(c, dent2, hash_dent2); | |
| 1260 | + if (err) | |
| 1261 | + goto out_release; | |
| 1165 | 1262 | |
| 1166 | 1263 | p = (void *)dent2 + aligned_dlen2; |
| 1167 | 1264 | if (new_inode) { |
| 1168 | 1265 | pack_inode(c, p, new_inode, 0); |
| 1266 | + err = ubifs_node_calc_hash(c, p, hash_new_inode); | |
| 1267 | + if (err) | |
| 1268 | + goto out_release; | |
| 1269 | + | |
| 1169 | 1270 | p += ALIGN(ilen, 8); |
| 1170 | 1271 | } |
| 1171 | 1272 | |
| 1172 | − if (!move) | |
| 1273 | + if (!move) { | |
| 1173 | 1274 | pack_inode(c, p, old_dir, 1); |
| 1174 | − else { | |
| 1275 | + err = ubifs_node_calc_hash(c, p, hash_old_dir); | |
| 1276 | + if (err) | |
| 1277 | + goto out_release; | |
| 1278 | + } else { | |
| 1175 | 1279 | pack_inode(c, p, old_dir, 0); |
| 1280 | + err = ubifs_node_calc_hash(c, p, hash_old_dir); | |
| 1281 | + if (err) | |
| 1282 | + goto out_release; | |
| 1283 | + | |
| 1176 | 1284 | p += ALIGN(plen, 8); |
| 1177 | 1285 | pack_inode(c, p, new_dir, 1); |
| 1286 | + err = ubifs_node_calc_hash(c, p, hash_new_dir); | |
| 1287 | + if (err) | |
| 1288 | + goto out_release; | |
| 1178 | 1289 | } |
| 1179 | 1290 | |
| 1180 | 1291 | if (last_reference) { |
| @@ -1200,15 +1311,17 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, · 19 unmodified lines | ||
| 1200 | 1311 | } |
| 1201 | 1312 | release_head(c, BASEHD); |
| 1202 | 1313 | |
| 1314 | + ubifs_add_auth_dirt(c, lnum); | |
| 1315 | + | |
| 1203 | 1316 | dent_key_init(c, &key, new_dir->i_ino, new_nm); |
| 1204 | − err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, new_nm); | |
| 1317 | + err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen1, hash_dent1, new_nm); | |
| 1205 | 1318 | if (err) |
| 1206 | 1319 | goto out_ro; |
| 1207 | 1320 | |
| 1208 | 1321 | offs += aligned_dlen1; |
| 1209 | 1322 | if (whiteout) { |
| 1210 | 1323 | dent_key_init(c, &key, old_dir->i_ino, old_nm); |
| 1211 | − err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, old_nm); | |
| 1324 | + err = ubifs_tnc_add_nm(c, &key, lnum, offs, dlen2, hash_dent2, old_nm); | |
| 1212 | 1325 | if (err) |
| 1213 | 1326 | goto out_ro; |
| 1214 | 1327 | |
| @@ -1227,21 +1340,21 @@ int ubifs_jnl_rename(struct ubifs_info *c, const struct inode *old_dir, · 12 unmodified lines | ||
| 1227 | 1340 | offs += aligned_dlen2; |
| 1228 | 1341 | if (new_inode) { |
| 1229 | 1342 | ino_key_init(c, &key, new_inode->i_ino); |
| 1230 | − err = ubifs_tnc_add(c, &key, lnum, offs, ilen); | |
| 1343 | + err = ubifs_tnc_add(c, &key, lnum, offs, ilen, hash_new_inode); | |
| 1231 | 1344 | if (err) |
| 1232 | 1345 | goto out_ro; |
| 1233 | 1346 | offs += ALIGN(ilen, 8); |
| 1234 | 1347 | } |
| 1235 | 1348 | |
| 1236 | 1349 | ino_key_init(c, &key, old_dir->i_ino); |
| 1237 | − err = ubifs_tnc_add(c, &key, lnum, offs, plen); | |
| 1350 | + err = ubifs_tnc_add(c, &key, lnum, offs, plen, hash_old_dir); | |
| 1238 | 1351 | if (err) |
| 1239 | 1352 | goto out_ro; |
| 1240 | 1353 | |
| 1241 | 1354 | if (move) { |
| 1242 | 1355 | offs += ALIGN(plen, 8); |
| 1243 | 1356 | ino_key_init(c, &key, new_dir->i_ino); |
| 1244 | − err = ubifs_tnc_add(c, &key, lnum, offs, plen); | |
| 1357 | + err = ubifs_tnc_add(c, &key, lnum, offs, plen, hash_new_dir); | |
| 1245 | 1358 | if (err) |
| 1246 | 1359 | goto out_ro; |
| 1247 | 1360 | } |
| @@ -1360,6 +1473,8 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode, · 112 unmodified lines | ||
| 1360 | 1473 | struct ubifs_inode *ui = ubifs_inode(inode); |
| 1361 | 1474 | ino_t inum = inode->i_ino; |
| 1362 | 1475 | unsigned int blk; |
| 1476 | + u8 hash_ino[UBIFS_HASH_ARR_SZ]; | |
| 1477 | + u8 hash_dn[UBIFS_HASH_ARR_SZ]; | |
| 1363 | 1478 | |
| 1364 | 1479 | dbg_jnl("ino %lu, size %lld -> %lld", |
| 1365 | 1480 | (unsigned long)inum, old_size, new_size); |
| @@ -1369,6 +1484,9 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode, · 3 unmodified lines | ||
| 1369 | 1484 | |
| 1370 | 1485 | sz = UBIFS_TRUN_NODE_SZ + UBIFS_INO_NODE_SZ + |
| 1371 | 1486 | UBIFS_MAX_DATA_NODE_SZ * WORST_COMPR_FACTOR; |
| 1487 | + | |
| 1488 | + sz += ubifs_auth_node_sz(c); | |
| 1489 | + | |
| 1372 | 1490 | ino = kmalloc(sz, GFP_NOFS); |
| 1373 | 1491 | if (!ino) |
| 1374 | 1492 | return -ENOMEM; |
| @@ -1414,16 +1532,28 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode, · 39 unmodified lines | ||
| 1414 | 1532 | |
| 1415 | 1533 | /* Must make reservation before allocating sequence numbers */ |
| 1416 | 1534 | len = UBIFS_TRUN_NODE_SZ + UBIFS_INO_NODE_SZ; |
| 1417 | − if (dlen) | |
| 1535 | + | |
| 1536 | + if (ubifs_authenticated(c)) | |
| 1537 | + len += ALIGN(dlen, 8) + ubifs_auth_node_sz(c); | |
| 1538 | + else | |
| 1418 | 1539 | len += dlen; |
| 1540 | + | |
| 1419 | 1541 | err = make_reservation(c, BASEHD, len); |
| 1420 | 1542 | if (err) |
| 1421 | 1543 | goto out_free; |
| 1422 | 1544 | |
| 1423 | 1545 | pack_inode(c, ino, inode, 0); |
| 1546 | + err = ubifs_node_calc_hash(c, ino, hash_ino); | |
| 1547 | + if (err) | |
| 1548 | + goto out_release; | |
| 1549 | + | |
| 1424 | 1550 | ubifs_prep_grp_node(c, trun, UBIFS_TRUN_NODE_SZ, dlen ? 0 : 1); |
| 1425 | − if (dlen) | |
| 1551 | + if (dlen) { | |
| 1426 | 1552 | ubifs_prep_grp_node(c, dn, dlen, 1); |
| 1553 | + err = ubifs_node_calc_hash(c, dn, hash_dn); | |
| 1554 | + if (err) | |
| 1555 | + goto out_release; | |
| 1556 | + } | |
| 1427 | 1557 | |
| 1428 | 1558 | err = write_head(c, BASEHD, ino, len, &lnum, &offs, sync); |
| 1429 | 1559 | if (err) |
| @@ -1432,15 +1562,17 @@ int ubifs_jnl_truncate(struct ubifs_info *c, const struct inode *inode, · 2 unmodified lines | ||
| 1432 | 1562 | ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, inum); |
| 1433 | 1563 | release_head(c, BASEHD); |
| 1434 | 1564 | |
| 1565 | + ubifs_add_auth_dirt(c, lnum); | |
| 1566 | + | |
| 1435 | 1567 | if (dlen) { |
| 1436 | 1568 | sz = offs + UBIFS_INO_NODE_SZ + UBIFS_TRUN_NODE_SZ; |
| 1437 | − err = ubifs_tnc_add(c, &key, lnum, sz, dlen); | |
| 1569 | + err = ubifs_tnc_add(c, &key, lnum, sz, dlen, hash_dn); | |
| 1438 | 1570 | if (err) |
| 1439 | 1571 | goto out_ro; |
| 1440 | 1572 | } |
| 1441 | 1573 | |
| 1442 | 1574 | ino_key_init(c, &key, inum); |
| 1443 | − err = ubifs_tnc_add(c, &key, lnum, offs, UBIFS_INO_NODE_SZ); | |
| 1575 | + err = ubifs_tnc_add(c, &key, lnum, offs, UBIFS_INO_NODE_SZ, hash_ino); | |
| 1444 | 1576 | if (err) |
| 1445 | 1577 | goto out_ro; |
| 1446 | 1578 | |
| @@ -1495,12 +1627,13 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, · 48 unmodified lines | ||
| 1495 | 1627 | const struct inode *inode, |
| 1496 | 1628 | const struct fscrypt_name *nm) |
| 1497 | 1629 | { |
| 1498 | − int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen; | |
| 1630 | + int err, xlen, hlen, len, lnum, xent_offs, aligned_xlen, write_len; | |
| 1499 | 1631 | struct ubifs_dent_node *xent; |
| 1500 | 1632 | struct ubifs_ino_node *ino; |
| 1501 | 1633 | union ubifs_key xent_key, key1, key2; |
| 1502 | 1634 | int sync = IS_DIRSYNC(host); |
| 1503 | 1635 | struct ubifs_inode *host_ui = ubifs_inode(host); |
| 1636 | + u8 hash[UBIFS_HASH_ARR_SZ]; | |
| 1504 | 1637 | |
| 1505 | 1638 | ubifs_assert(c, inode->i_nlink == 0); |
| 1506 | 1639 | ubifs_assert(c, mutex_is_locked(&host_ui->ui_mutex)); |
| @@ -1514,12 +1647,14 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, · 7 unmodified lines | ||
| 1514 | 1647 | hlen = host_ui->data_len + UBIFS_INO_NODE_SZ; |
| 1515 | 1648 | len = aligned_xlen + UBIFS_INO_NODE_SZ + ALIGN(hlen, 8); |
| 1516 | 1649 | |
| 1517 | − xent = kzalloc(len, GFP_NOFS); | |
| 1650 | + write_len = len + ubifs_auth_node_sz(c); | |
| 1651 | + | |
| 1652 | + xent = kzalloc(write_len, GFP_NOFS); | |
| 1518 | 1653 | if (!xent) |
| 1519 | 1654 | return -ENOMEM; |
| 1520 | 1655 | |
| 1521 | 1656 | /* Make reservation before allocating sequence numbers */ |
| 1522 | − err = make_reservation(c, BASEHD, len); | |
| 1657 | + err = make_reservation(c, BASEHD, write_len); | |
| 1523 | 1658 | if (err) { |
| 1524 | 1659 | kfree(xent); |
| 1525 | 1660 | return err; |
| @@ -1540,11 +1675,16 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, · 14 unmodified lines | ||
| 1540 | 1675 | pack_inode(c, ino, inode, 0); |
| 1541 | 1676 | ino = (void *)ino + UBIFS_INO_NODE_SZ; |
| 1542 | 1677 | pack_inode(c, ino, host, 1); |
| 1678 | + err = ubifs_node_calc_hash(c, ino, hash); | |
| 1679 | + if (err) | |
| 1680 | + goto out_release; | |
| 1543 | 1681 | |
| 1544 | − err = write_head(c, BASEHD, xent, len, &lnum, &xent_offs, sync); | |
| 1682 | + err = write_head(c, BASEHD, xent, write_len, &lnum, &xent_offs, sync); | |
| 1545 | 1683 | if (!sync && !err) |
| 1546 | 1684 | ubifs_wbuf_add_ino_nolock(&c->jheads[BASEHD].wbuf, host->i_ino); |
| 1547 | 1685 | release_head(c, BASEHD); |
| 1686 | + | |
| 1687 | + ubifs_add_auth_dirt(c, lnum); | |
| 1548 | 1688 | kfree(xent); |
| 1549 | 1689 | if (err) |
| 1550 | 1690 | goto out_ro; |
| @@ -1572,7 +1712,7 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, · 21 unmodified lines | ||
| 1572 | 1712 | |
| 1573 | 1713 | /* And update TNC with the new host inode position */ |
| 1574 | 1714 | ino_key_init(c, &key1, host->i_ino); |
| 1575 | − err = ubifs_tnc_add(c, &key1, lnum, xent_offs + len - hlen, hlen); | |
| 1715 | + err = ubifs_tnc_add(c, &key1, lnum, xent_offs + len - hlen, hlen, hash); | |
| 1576 | 1716 | if (err) |
| 1577 | 1717 | goto out_ro; |
| 1578 | 1718 | |
| @@ -1583,6 +1723,9 @@ int ubifs_jnl_delete_xattr(struct ubifs_info *c, const struct inode *host, · 4 unmodified lines | ||
| 1583 | 1723 | mark_inode_clean(c, host_ui); |
| 1584 | 1724 | return 0; |
| 1585 | 1725 | |
| 1726 | +out_release: | |
| 1727 | + kfree(xent); | |
| 1728 | + release_head(c, BASEHD); | |
| 1586 | 1729 | out_ro: |
| 1587 | 1730 | ubifs_ro_mode(c, err); |
| 1588 | 1731 | finish_reservation(c); |
| @@ -1610,6 +1753,8 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode, · 21 unmodified lines | ||
| 1610 | 1753 | struct ubifs_ino_node *ino; |
| 1611 | 1754 | union ubifs_key key; |
| 1612 | 1755 | int sync = IS_DIRSYNC(host); |
| 1756 | + u8 hash_host[UBIFS_HASH_ARR_SZ]; | |
| 1757 | + u8 hash[UBIFS_HASH_ARR_SZ]; | |
| 1613 | 1758 | |
| 1614 | 1759 | dbg_jnl("ino %lu, ino %lu", host->i_ino, inode->i_ino); |
| 1615 | 1760 | ubifs_assert(c, host->i_nlink > 0); |
| @@ -1621,6 +1766,8 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode, · 5 unmodified lines | ||
| 1621 | 1766 | aligned_len1 = ALIGN(len1, 8); |
| 1622 | 1767 | aligned_len = aligned_len1 + ALIGN(len2, 8); |
| 1623 | 1768 | |
| 1769 | + aligned_len += ubifs_auth_node_sz(c); | |
| 1770 | + | |
| 1624 | 1771 | ino = kzalloc(aligned_len, GFP_NOFS); |
| 1625 | 1772 | if (!ino) |
| 1626 | 1773 | return -ENOMEM; |
| @@ -1631,7 +1778,13 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode, · 4 unmodified lines | ||
| 1631 | 1778 | goto out_free; |
| 1632 | 1779 | |
| 1633 | 1780 | pack_inode(c, ino, host, 0); |
| 1781 | + err = ubifs_node_calc_hash(c, ino, hash_host); | |
| 1782 | + if (err) | |
| 1783 | + goto out_release; | |
| 1634 | 1784 | pack_inode(c, (void *)ino + aligned_len1, inode, 1); |
| 1785 | + err = ubifs_node_calc_hash(c, (void *)ino + aligned_len1, hash); | |
| 1786 | + if (err) | |
| 1787 | + goto out_release; | |
| 1635 | 1788 | |
| 1636 | 1789 | err = write_head(c, BASEHD, ino, aligned_len, &lnum, &offs, 0); |
| 1637 | 1790 | if (!sync && !err) { |
| @@ -1644,13 +1797,15 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode, · 6 unmodified lines | ||
| 1644 | 1797 | if (err) |
| 1645 | 1798 | goto out_ro; |
| 1646 | 1799 | |
| 1800 | + ubifs_add_auth_dirt(c, lnum); | |
| 1801 | + | |
| 1647 | 1802 | ino_key_init(c, &key, host->i_ino); |
| 1648 | − err = ubifs_tnc_add(c, &key, lnum, offs, len1); | |
| 1803 | + err = ubifs_tnc_add(c, &key, lnum, offs, len1, hash_host); | |
| 1649 | 1804 | if (err) |
| 1650 | 1805 | goto out_ro; |
| 1651 | 1806 | |
| 1652 | 1807 | ino_key_init(c, &key, inode->i_ino); |
| 1653 | − err = ubifs_tnc_add(c, &key, lnum, offs + aligned_len1, len2); | |
| 1808 | + err = ubifs_tnc_add(c, &key, lnum, offs + aligned_len1, len2, hash); | |
| 1654 | 1809 | if (err) |
| 1655 | 1810 | goto out_ro; |
| 1656 | 1811 | |
| @@ -1662,6 +1817,8 @@ int ubifs_jnl_change_xattr(struct ubifs_info *c, const struct inode *inode, · 5 unmodified lines | ||
| 1662 | 1817 | kfree(ino); |
| 1663 | 1818 | return 0; |
| 1664 | 1819 | |
| 1820 | +out_release: | |
| 1821 | + release_head(c, BASEHD); | |
| 1665 | 1822 | out_ro: |
| 1666 | 1823 | ubifs_ro_mode(c, err); |
| 1667 | 1824 | finish_reservation(c); |
| @@ -236,6 +236,7 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs) · 235 unmodified lines | ||
| 236 | 236 | bud->lnum = lnum; |
| 237 | 237 | bud->start = offs; |
| 238 | 238 | bud->jhead = jhead; |
| 239 | + bud->log_hash = NULL; | |
| 239 | 240 | |
| 240 | 241 | ref->ch.node_type = UBIFS_REF_NODE; |
| 241 | 242 | ref->lnum = cpu_to_le32(bud->lnum); |
| @@ -275,6 +276,14 @@ int ubifs_add_bud_to_log(struct ubifs_info *c, int jhead, int lnum, int offs) · 33 unmodified lines | ||
| 275 | 276 | if (err) |
| 276 | 277 | goto out_unlock; |
| 277 | 278 | |
| 279 | + err = ubifs_shash_update(c, c->log_hash, ref, UBIFS_REF_NODE_SZ); | |
| 280 | + if (err) | |
| 281 | + goto out_unlock; | |
| 282 | + | |
| 283 | + err = ubifs_shash_copy_state(c, c->log_hash, c->jheads[jhead].log_hash); | |
| 284 | + if (err) | |
| 285 | + goto out_unlock; | |
| 286 | + | |
| 278 | 287 | c->lhead_offs += c->ref_node_alsz; |
| 279 | 288 | |
| 280 | 289 | ubifs_add_bud(c, bud); |
| @@ -377,6 +386,14 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) · 96 unmodified lines | ||
| 377 | 386 | cs->cmt_no = cpu_to_le64(c->cmt_no); |
| 378 | 387 | ubifs_prepare_node(c, cs, UBIFS_CS_NODE_SZ, 0); |
| 379 | 388 | |
| 389 | + err = ubifs_shash_init(c, c->log_hash); | |
| 390 | + if (err) | |
| 391 | + goto out; | |
| 392 | + | |
| 393 | + err = ubifs_shash_update(c, c->log_hash, cs, UBIFS_CS_NODE_SZ); | |
| 394 | + if (err < 0) | |
| 395 | + goto out; | |
| 396 | + | |
| 380 | 397 | /* |
| 381 | 398 | * Note, we do not lock 'c->log_mutex' because this is the commit start |
| 382 | 399 | * phase and we are exclusively using the log. And we do not lock |
| @@ -402,6 +419,12 @@ int ubifs_log_start_commit(struct ubifs_info *c, int *ltail_lnum) · 19 unmodified lines | ||
| 402 | 419 | |
| 403 | 420 | ubifs_prepare_node(c, ref, UBIFS_REF_NODE_SZ, 0); |
| 404 | 421 | len += UBIFS_REF_NODE_SZ; |
| 422 | + | |
| 423 | + err = ubifs_shash_update(c, c->log_hash, ref, | |
| 424 | + UBIFS_REF_NODE_SZ); | |
| 425 | + if (err) | |
| 426 | + goto out; | |
| 427 | + ubifs_shash_copy_state(c, c->log_hash, c->jheads[i].log_hash); | |
| 405 | 428 | } |
| 406 | 429 | |
| 407 | 430 | ubifs_pad(c, buf + len, ALIGN(len, c->min_io_size) - len); |
| @@ -516,6 +539,7 @@ int ubifs_log_post_commit(struct ubifs_info *c, int old_ltail_lnum) · 108 unmodified lines | ||
| 516 | 539 | if (err) |
| 517 | 540 | return err; |
| 518 | 541 | list_del(&bud->list); |
| 542 | + kfree(bud->log_hash); | |
| 519 | 543 | kfree(bud); |
| 520 | 544 | } |
| 521 | 545 | mutex_lock(&c->log_mutex); |
| @@ -604,11 +604,12 @@ static int calc_pnode_num_from_parent(const struct ubifs_info *c, · 603 unmodified lines | ||
| 604 | 604 | * @lpt_first: LEB number of first LPT LEB |
| 605 | 605 | * @lpt_lebs: number of LEBs for LPT is passed and returned here |
| 606 | 606 | * @big_lpt: use big LPT model is passed and returned here |
| 607 | + * @hash: hash of the LPT is returned here | |
| 607 | 608 | * |
| 608 | 609 | * This function returns %0 on success and a negative error code on failure. |
| 609 | 610 | */ |
| 610 | 611 | int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, |
| 611 | − int *lpt_lebs, int *big_lpt) | |
| 612 | + int *lpt_lebs, int *big_lpt, u8 *hash) | |
| 612 | 613 | { |
| 613 | 614 | int lnum, err = 0, node_sz, iopos, i, j, cnt, len, alen, row; |
| 614 | 615 | int blnum, boffs, bsz, bcnt; |
| @@ -617,6 +618,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, · 2 unmodified lines | ||
| 617 | 618 | void *buf = NULL, *p; |
| 618 | 619 | struct ubifs_lpt_lprops *ltab = NULL; |
| 619 | 620 | int *lsave = NULL; |
| 621 | + struct shash_desc *desc; | |
| 620 | 622 | |
| 621 | 623 | err = calc_dflt_lpt_geom(c, main_lebs, big_lpt); |
| 622 | 624 | if (err) |
| @@ -630,6 +632,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, · 7 unmodified lines | ||
| 630 | 632 | /* Needed by 'ubifs_pack_lsave()' */ |
| 631 | 633 | c->main_first = c->leb_cnt - *main_lebs; |
| 632 | 634 | |
| 635 | + desc = ubifs_hash_get_desc(c); | |
| 636 | + if (IS_ERR(desc)) | |
| 637 | + return PTR_ERR(desc); | |
| 638 | + | |
| 633 | 639 | lsave = kmalloc_array(c->lsave_cnt, sizeof(int), GFP_KERNEL); |
| 634 | 640 | pnode = kzalloc(sizeof(struct ubifs_pnode), GFP_KERNEL); |
| 635 | 641 | nnode = kzalloc(sizeof(struct ubifs_nnode), GFP_KERNEL); |
| @@ -677,6 +683,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, · 41 unmodified lines | ||
| 677 | 683 | |
| 678 | 684 | /* Add first pnode */ |
| 679 | 685 | ubifs_pack_pnode(c, p, pnode); |
| 686 | + err = ubifs_shash_update(c, desc, p, c->pnode_sz); | |
| 687 | + if (err) | |
| 688 | + goto out; | |
| 689 | + | |
| 680 | 690 | p += c->pnode_sz; |
| 681 | 691 | len = c->pnode_sz; |
| 682 | 692 | pnode->num += 1; |
| @@ -711,6 +721,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, · 28 unmodified lines | ||
| 711 | 721 | len = 0; |
| 712 | 722 | } |
| 713 | 723 | ubifs_pack_pnode(c, p, pnode); |
| 724 | + err = ubifs_shash_update(c, desc, p, c->pnode_sz); | |
| 725 | + if (err) | |
| 726 | + goto out; | |
| 727 | + | |
| 714 | 728 | p += c->pnode_sz; |
| 715 | 729 | len += c->pnode_sz; |
| 716 | 730 | /* |
| @@ -830,6 +844,10 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, · 113 unmodified lines | ||
| 830 | 844 | if (err) |
| 831 | 845 | goto out; |
| 832 | 846 | |
| 847 | + err = ubifs_shash_final(c, desc, hash); | |
| 848 | + if (err) | |
| 849 | + goto out; | |
| 850 | + | |
| 833 | 851 | c->nhead_lnum = lnum; |
| 834 | 852 | c->nhead_offs = ALIGN(len, c->min_io_size); |
| 835 | 853 | |
| @@ -853,6 +871,7 @@ int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, · 17 unmodified lines | ||
| 853 | 871 | dbg_lp("LPT lsave is at %d:%d", c->lsave_lnum, c->lsave_offs); |
| 854 | 872 | out: |
| 855 | 873 | c->ltab = NULL; |
| 874 | + kfree(desc); | |
| 856 | 875 | kfree(lsave); |
| 857 | 876 | vfree(ltab); |
| 858 | 877 | vfree(buf); |
| @@ -1439,26 +1458,25 @@ struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c, · 580 unmodified lines | ||
| 1439 | 1458 | } |
| 1440 | 1459 | |
| 1441 | 1460 | /** |
| 1442 | − * ubifs_lpt_lookup - lookup LEB properties in the LPT. | |
| 1461 | + * ubifs_pnode_lookup - lookup a pnode in the LPT. | |
| 1443 | 1462 | * @c: UBIFS file-system description object |
| 1444 | − * @lnum: LEB number to lookup | |
| 1463 | + * @i: pnode number (0 to (main_lebs - 1) / UBIFS_LPT_FANOUT) | |
| 1445 | 1464 | * |
| 1446 | − * This function returns a pointer to the LEB properties on success or a | |
| 1447 | − * negative error code on failure. | |
| 1465 | + * This function returns a pointer to the pnode on success or a negative | |
| 1466 | + * error code on failure. | |
| 1448 | 1467 | */ |
| 1449 | −struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum) | |
| 1468 | +struct ubifs_pnode *ubifs_pnode_lookup(struct ubifs_info *c, int i) | |
| 1450 | 1469 | { |
| 1451 | − int err, i, h, iip, shft; | |
| 1470 | + int err, h, iip, shft; | |
| 1452 | 1471 | struct ubifs_nnode *nnode; |
| 1453 | − struct ubifs_pnode *pnode; | |
| 1454 | 1472 | |
| 1455 | 1473 | if (!c->nroot) { |
| 1456 | 1474 | err = ubifs_read_nnode(c, NULL, 0); |
| 1457 | 1475 | if (err) |
| 1458 | 1476 | return ERR_PTR(err); |
| 1459 | 1477 | } |
| 1478 | + i <<= UBIFS_LPT_FANOUT_SHIFT; | |
| 1460 | 1479 | nnode = c->nroot; |
| 1461 | − i = lnum - c->main_first; | |
| 1462 | 1480 | shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; |
| 1463 | 1481 | for (h = 1; h < c->lpt_hght; h++) { |
| 1464 | 1482 | iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); |
| @@ -1468,7 +1486,24 @@ struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum) · 3 unmodified lines | ||
| 1468 | 1486 | return ERR_CAST(nnode); |
| 1469 | 1487 | } |
| 1470 | 1488 | iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); |
| 1471 | − pnode = ubifs_get_pnode(c, nnode, iip); | |
| 1489 | + return ubifs_get_pnode(c, nnode, iip); | |
| 1490 | +} | |
| 1491 | + | |
| 1492 | +/** | |
| 1493 | + * ubifs_lpt_lookup - lookup LEB properties in the LPT. | |
| 1494 | + * @c: UBIFS file-system description object | |
| 1495 | + * @lnum: LEB number to lookup | |
| 1496 | + * | |
| 1497 | + * This function returns a pointer to the LEB properties on success or a | |
| 1498 | + * negative error code on failure. | |
| 1499 | + */ | |
| 1500 | +struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum) | |
| 1501 | +{ | |
| 1502 | + int i, iip; | |
| 1503 | + struct ubifs_pnode *pnode; | |
| 1504 | + | |
| 1505 | + i = lnum - c->main_first; | |
| 1506 | + pnode = ubifs_pnode_lookup(c, i >> UBIFS_LPT_FANOUT_SHIFT); | |
| 1472 | 1507 | if (IS_ERR(pnode)) |
| 1473 | 1508 | return ERR_CAST(pnode); |
| 1474 | 1509 | iip = (i & (UBIFS_LPT_FANOUT - 1)); |
| @@ -1619,6 +1654,131 @@ struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum) · 144 unmodified lines | ||
| 1619 | 1654 | return &pnode->lprops[iip]; |
| 1620 | 1655 | } |
| 1621 | 1656 | |
| 1657 | +/** | |
| 1658 | + * ubifs_lpt_calc_hash - Calculate hash of the LPT pnodes | |
| 1659 | + * @c: UBIFS file-system description object | |
| 1660 | + * @hash: the returned hash of the LPT pnodes | |
| 1661 | + * | |
| 1662 | + * This function iterates over the LPT pnodes and creates a hash over them. | |
| 1663 | + * Returns 0 for success or a negative error code otherwise. | |
| 1664 | + */ | |
| 1665 | +int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash) | |
| 1666 | +{ | |
| 1667 | + struct ubifs_nnode *nnode, *nn; | |
| 1668 | + struct ubifs_cnode *cnode; | |
| 1669 | + struct shash_desc *desc; | |
| 1670 | + int iip = 0, i; | |
| 1671 | + int bufsiz = max_t(int, c->nnode_sz, c->pnode_sz); | |
| 1672 | + void *buf; | |
| 1673 | + int err; | |
| 1674 | + | |
| 1675 | + if (!ubifs_authenticated(c)) | |
| 1676 | + return 0; | |
| 1677 | + | |
| 1678 | + desc = ubifs_hash_get_desc(c); | |
| 1679 | + if (IS_ERR(desc)) | |
| 1680 | + return PTR_ERR(desc); | |
| 1681 | + | |
| 1682 | + buf = kmalloc(bufsiz, GFP_NOFS); | |
| 1683 | + if (!buf) { | |
| 1684 | + err = -ENOMEM; | |
| 1685 | + goto out; | |
| 1686 | + } | |
| 1687 | + | |
| 1688 | + if (!c->nroot) { | |
| 1689 | + err = ubifs_read_nnode(c, NULL, 0); | |
| 1690 | + if (err) | |
| 1691 | + return err; | |
| 1692 | + } | |
| 1693 | + | |
| 1694 | + cnode = (struct ubifs_cnode *)c->nroot; | |
| 1695 | + | |
| 1696 | + while (cnode) { | |
| 1697 | + nnode = cnode->parent; | |
| 1698 | + nn = (struct ubifs_nnode *)cnode; | |
| 1699 | + if (cnode->level > 1) { | |
| 1700 | + while (iip < UBIFS_LPT_FANOUT) { | |
| 1701 | + if (nn->nbranch[iip].lnum == 0) { | |
| 1702 | + /* Go right */ | |
| 1703 | + iip++; | |
| 1704 | + continue; | |
| 1705 | + } | |
| 1706 | + | |
| 1707 | + nnode = ubifs_get_nnode(c, nn, iip); | |
| 1708 | + if (IS_ERR(nnode)) { | |
| 1709 | + err = PTR_ERR(nnode); | |
| 1710 | + goto out; | |
| 1711 | + } | |
| 1712 | + | |
| 1713 | + /* Go down */ | |
| 1714 | + iip = 0; | |
| 1715 | + cnode = (struct ubifs_cnode *)nnode; | |
| 1716 | + break; | |
| 1717 | + } | |
| 1718 | + if (iip < UBIFS_LPT_FANOUT) | |
| 1719 | + continue; | |
| 1720 | + } else { | |
| 1721 | + struct ubifs_pnode *pnode; | |
| 1722 | + | |
| 1723 | + for (i = 0; i < UBIFS_LPT_FANOUT; i++) { | |
| 1724 | + if (nn->nbranch[i].lnum == 0) | |
| 1725 | + continue; | |
| 1726 | + pnode = ubifs_get_pnode(c, nn, i); | |
| 1727 | + if (IS_ERR(pnode)) { | |
| 1728 | + err = PTR_ERR(pnode); | |
| 1729 | + goto out; | |
| 1730 | + } | |
| 1731 | + | |
| 1732 | + ubifs_pack_pnode(c, buf, pnode); | |
| 1733 | + err = ubifs_shash_update(c, desc, buf, | |
| 1734 | + c->pnode_sz); | |
| 1735 | + if (err) | |
| 1736 | + goto out; | |
| 1737 | + } | |
| 1738 | + } | |
| 1739 | + /* Go up and to the right */ | |
| 1740 | + iip = cnode->iip + 1; | |
| 1741 | + cnode = (struct ubifs_cnode *)nnode; | |
| 1742 | + } | |
| 1743 | + | |
| 1744 | + err = ubifs_shash_final(c, desc, hash); | |
| 1745 | +out: | |
| 1746 | + kfree(desc); | |
| 1747 | + kfree(buf); | |
| 1748 | + | |
| 1749 | + return err; | |
| 1750 | +} | |
| 1751 | + | |
| 1752 | +/** | |
| 1753 | + * lpt_check_hash - check the hash of the LPT. | |
| 1754 | + * @c: UBIFS file-system description object | |
| 1755 | + * | |
| 1756 | + * This function calculates a hash over all pnodes in the LPT and compares it with | |
| 1757 | + * the hash stored in the master node. Returns %0 on success and a negative error | |
| 1758 | + * code on failure. | |
| 1759 | + */ | |
| 1760 | +static int lpt_check_hash(struct ubifs_info *c) | |
| 1761 | +{ | |
| 1762 | + int err; | |
| 1763 | + u8 hash[UBIFS_HASH_ARR_SZ]; | |
| 1764 | + | |
| 1765 | + if (!ubifs_authenticated(c)) | |
| 1766 | + return 0; | |
| 1767 | + | |
| 1768 | + err = ubifs_lpt_calc_hash(c, hash); | |
| 1769 | + if (err) | |
| 1770 | + return err; | |
| 1771 | + | |
| 1772 | + if (ubifs_check_hash(c, c->mst_node->hash_lpt, hash)) { | |
| 1773 | + err = -EPERM; | |
| 1774 | + ubifs_err(c, "Failed to authenticate LPT"); | |
| 1775 | + } else { | |
| 1776 | + err = 0; | |
| 1777 | + } | |
| 1778 | + | |
| 1779 | + return err; | |
| 1780 | +} | |
| 1781 | + | |
| 1622 | 1782 | /** |
| 1623 | 1783 | * lpt_init_rd - initialize the LPT for reading. |
| 1624 | 1784 | * @c: UBIFS file-system description object |
| @@ -1660,6 +1820,10 @@ static int lpt_init_rd(struct ubifs_info *c) · 35 unmodified lines | ||
| 1660 | 1820 | if (err) |
| 1661 | 1821 | return err; |
| 1662 | 1822 | |
| 1823 | + err = lpt_check_hash(c); | |
| 1824 | + if (err) | |
| 1825 | + return err; | |
| 1826 | + | |
| 1663 | 1827 | dbg_lp("space_bits %d", c->space_bits); |
| 1664 | 1828 | dbg_lp("lpt_lnum_bits %d", c->lpt_lnum_bits); |
| 1665 | 1829 | dbg_lp("lpt_offs_bits %d", c->lpt_offs_bits); |
| @@ -618,38 +618,6 @@ static struct ubifs_pnode *next_pnode_to_dirty(struct ubifs_info *c, · 617 unmodified lines | ||
| 618 | 618 | return ubifs_get_pnode(c, nnode, iip); |
| 619 | 619 | } |
| 620 | 620 | |
| 621 | −/** | |
| 622 | − * pnode_lookup - lookup a pnode in the LPT. | |
| 623 | − * @c: UBIFS file-system description object | |
| 624 | − * @i: pnode number (0 to (main_lebs - 1) / UBIFS_LPT_FANOUT)) | |
| 625 | − * | |
| 626 | − * This function returns a pointer to the pnode on success or a negative | |
| 627 | − * error code on failure. | |
| 628 | − */ | |
| 629 | −static struct ubifs_pnode *pnode_lookup(struct ubifs_info *c, int i) | |
| 630 | −{ | |
| 631 | − int err, h, iip, shft; | |
| 632 | − struct ubifs_nnode *nnode; | |
| 633 | − | |
| 634 | − if (!c->nroot) { | |
| 635 | − err = ubifs_read_nnode(c, NULL, 0); | |
| 636 | − if (err) | |
| 637 | − return ERR_PTR(err); | |
| 638 | − } | |
| 639 | − i <<= UBIFS_LPT_FANOUT_SHIFT; | |
| 640 | − nnode = c->nroot; | |
| 641 | − shft = c->lpt_hght * UBIFS_LPT_FANOUT_SHIFT; | |
| 642 | − for (h = 1; h < c->lpt_hght; h++) { | |
| 643 | − iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); | |
| 644 | − shft -= UBIFS_LPT_FANOUT_SHIFT; | |
| 645 | − nnode = ubifs_get_nnode(c, nnode, iip); | |
| 646 | − if (IS_ERR(nnode)) | |
| 647 | − return ERR_CAST(nnode); | |
| 648 | − } | |
| 649 | − iip = ((i >> shft) & (UBIFS_LPT_FANOUT - 1)); | |
| 650 | − return ubifs_get_pnode(c, nnode, iip); | |
| 651 | −} | |
| 652 | − | |
| 653 | 621 | /** |
| 654 | 622 | * add_pnode_dirt - add dirty space to LPT LEB properties. |
| 655 | 623 | * @c: UBIFS file-system description object |
| @@ -702,7 +670,7 @@ static int make_tree_dirty(struct ubifs_info *c) · 46 unmodified lines | ||
| 702 | 670 | { |
| 703 | 671 | struct ubifs_pnode *pnode; |
| 704 | 672 | |
| 705 | − pnode = pnode_lookup(c, 0); | |
| 673 | + pnode = ubifs_pnode_lookup(c, 0); | |
| 706 | 674 | if (IS_ERR(pnode)) |
| 707 | 675 | return PTR_ERR(pnode); |
| 708 | 676 | |
| @@ -956,7 +924,7 @@ static int make_pnode_dirty(struct ubifs_info *c, int node_num, int lnum, · 247 unmodified lines | ||
| 956 | 924 | struct ubifs_pnode *pnode; |
| 957 | 925 | struct ubifs_nbranch *branch; |
| 958 | 926 | |
| 959 | − pnode = pnode_lookup(c, node_num); | |
| 927 | + pnode = ubifs_pnode_lookup(c, node_num); | |
| 960 | 928 | if (IS_ERR(pnode)) |
| 961 | 929 | return PTR_ERR(pnode); |
| 962 | 930 | branch = &pnode->parent->nbranch[pnode->iip]; |
| @@ -1279,6 +1247,10 @@ int ubifs_lpt_start_commit(struct ubifs_info *c) · 316 unmodified lines | ||
| 1279 | 1247 | if (err) |
| 1280 | 1248 | goto out; |
| 1281 | 1249 | |
| 1250 | + err = ubifs_lpt_calc_hash(c, c->mst_node->hash_lpt); | |
| 1251 | + if (err) | |
| 1252 | + goto out; | |
| 1253 | + | |
| 1282 | 1254 | /* Copy the LPT's own lprops for end commit to write */ |
| 1283 | 1255 | memcpy(c->ltab_cmt, c->ltab, |
| 1284 | 1256 | sizeof(struct ubifs_lpt_lprops) * c->lpt_lebs); |
| @@ -1558,7 +1530,7 @@ static int dbg_is_pnode_dirty(struct ubifs_info *c, int lnum, int offs) · 273 unmodified lines | ||
| 1558 | 1530 | struct ubifs_nbranch *branch; |
| 1559 | 1531 | |
| 1560 | 1532 | cond_resched(); |
| 1561 | − pnode = pnode_lookup(c, i); | |
| 1533 | + pnode = ubifs_pnode_lookup(c, i); | |
| 1562 | 1534 | if (IS_ERR(pnode)) |
| 1563 | 1535 | return PTR_ERR(pnode); |
| 1564 | 1536 | branch = &pnode->parent->nbranch[pnode->iip]; |
| @@ -1710,7 +1682,7 @@ int dbg_check_ltab(struct ubifs_info *c) · 145 unmodified lines | ||
| 1710 | 1682 | for (i = 0; i < cnt; i++) { |
| 1711 | 1683 | struct ubifs_pnode *pnode; |
| 1712 | 1684 | |
| 1713 | − pnode = pnode_lookup(c, i); | |
| 1685 | + pnode = ubifs_pnode_lookup(c, i); | |
| 1714 | 1686 | if (IS_ERR(pnode)) |
| 1715 | 1687 | return PTR_ERR(pnode); |
| 1716 | 1688 | cond_resched(); |
| @@ -24,6 +24,42 @@ · 23 unmodified lines | ||
| 24 | 24 | |
| 25 | 25 | #include "ubifs.h" |
| 26 | 26 | |
| 27 | +/** | |
| 28 | + * ubifs_compare_master_node - compare two UBIFS master nodes | |
| 29 | + * @c: UBIFS file-system description object | |
| 30 | + * @m1: the first node | |
| 31 | + * @m2: the second node | |
| 32 | + * | |
| 33 | + * This function compares two UBIFS master nodes. Returns 0 if they are equal | |
| 34 | + * and nonzero if not. | |
| 35 | + */ | |
| 36 | +int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2) | |
| 37 | +{ | |
| 38 | + int ret; | |
| 39 | + int behind; | |
| 40 | + int hmac_offs = offsetof(struct ubifs_mst_node, hmac); | |
| 41 | + | |
| 42 | + /* | |
| 43 | + * Do not compare the common node header since the sequence number and | |
| 44 | + * hence the CRC are different. | |
| 45 | + */ | |
| 46 | + ret = memcmp(m1 + UBIFS_CH_SZ, m2 + UBIFS_CH_SZ, | |
| 47 | + hmac_offs - UBIFS_CH_SZ); | |
| 48 | + if (ret) | |
| 49 | + return ret; | |
| 50 | + | |
| 51 | + /* | |
| 52 | + * Do not compare the embedded HMAC aswell which also must be different | |
| 53 | + * due to the different common node header. | |
| 54 | + */ | |
| 55 | + behind = hmac_offs + UBIFS_MAX_HMAC_LEN; | |
| 56 | + | |
| 57 | + if (UBIFS_MST_NODE_SZ > behind) | |
| 58 | + return memcmp(m1 + behind, m2 + behind, UBIFS_MST_NODE_SZ - behind); | |
| 59 | + | |
| 60 | + return 0; | |
| 61 | +} | |
| 62 | + | |
| 27 | 63 | /** |
| 28 | 64 | * scan_for_master - search the valid master node. |
| 29 | 65 | * @c: UBIFS file-system description object |
| @@ -37,7 +73,7 @@ static int scan_for_master(struct ubifs_info *c) · 7 unmodified lines | ||
| 37 | 73 | { |
| 38 | 74 | struct ubifs_scan_leb *sleb; |
| 39 | 75 | struct ubifs_scan_node *snod; |
| 40 | − int lnum, offs = 0, nodes_cnt; | |
| 76 | + int lnum, offs = 0, nodes_cnt, err; | |
| 41 | 77 | |
| 42 | 78 | lnum = UBIFS_MST_LNUM; |
| 43 | 79 | |
| @@ -69,12 +105,23 @@ static int scan_for_master(struct ubifs_info *c) · 25 unmodified lines | ||
| 69 | 105 | goto out_dump; |
| 70 | 106 | if (snod->offs != offs) |
| 71 | 107 | goto out; |
| 72 | − if (memcmp((void *)c->mst_node + UBIFS_CH_SZ, | |
| 73 | − (void *)snod->node + UBIFS_CH_SZ, | |
| 74 | − UBIFS_MST_NODE_SZ - UBIFS_CH_SZ)) | |
| 108 | + if (ubifs_compare_master_node(c, c->mst_node, snod->node)) | |
| 75 | 109 | goto out; |
| 110 | + | |
| 76 | 111 | c->mst_offs = offs; |
| 77 | 112 | ubifs_scan_destroy(sleb); |
| 113 | + | |
| 114 | + if (!ubifs_authenticated(c)) | |
| 115 | + return 0; | |
| 116 | + | |
| 117 | + err = ubifs_node_verify_hmac(c, c->mst_node, | |
| 118 | + sizeof(struct ubifs_mst_node), | |
| 119 | + offsetof(struct ubifs_mst_node, hmac)); | |
| 120 | + if (err) { | |
| 121 | + ubifs_err(c, "Failed to verify master node HMAC"); | |
| 122 | + return -EPERM; | |
| 123 | + } | |
| 124 | + | |
| 78 | 125 | return 0; |
| 79 | 126 | |
| 80 | 127 | out: |
| @@ -305,6 +352,8 @@ int ubifs_read_master(struct ubifs_info *c) · 224 unmodified lines | ||
| 305 | 352 | c->lst.total_dead = le64_to_cpu(c->mst_node->total_dead); |
| 306 | 353 | c->lst.total_dark = le64_to_cpu(c->mst_node->total_dark); |
| 307 | 354 | |
| 355 | + ubifs_copy_hash(c, c->mst_node->hash_root_idx, c->zroot.hash); | |
| 356 | + | |
| 308 | 357 | c->calc_idx_sz = c->bi.old_idx_sz; |
| 309 | 358 | |
| 310 | 359 | if (c->mst_node->flags & cpu_to_le32(UBIFS_MST_NO_ORPHS)) |
| @@ -378,7 +427,9 @@ int ubifs_write_master(struct ubifs_info *c) · 67 unmodified lines | ||
| 378 | 427 | c->mst_offs = offs; |
| 379 | 428 | c->mst_node->highest_inum = cpu_to_le64(c->highest_inum); |
| 380 | 429 | |
| 381 | − err = ubifs_write_node(c, c->mst_node, len, lnum, offs); | |
| 430 | + ubifs_copy_hash(c, c->zroot.hash, c->mst_node->hash_root_idx); | |
| 431 | + err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs, | |
| 432 | + offsetof(struct ubifs_mst_node, hmac)); | |
| 382 | 433 | if (err) |
| 383 | 434 | return err; |
| 384 | 435 | |
| @@ -389,7 +440,8 @@ int ubifs_write_master(struct ubifs_info *c) · 4 unmodified lines | ||
| 389 | 440 | if (err) |
| 390 | 441 | return err; |
| 391 | 442 | } |
| 392 | − err = ubifs_write_node(c, c->mst_node, len, lnum, offs); | |
| 443 | + err = ubifs_write_node_hmac(c, c->mst_node, len, lnum, offs, | |
| 444 | + offsetof(struct ubifs_mst_node, hmac)); | |
| 393 | 445 | |
| 394 | 446 | return err; |
| 395 | 447 | } |
| @@ -197,7 +197,8 @@ static inline int ubifs_return_leb(struct ubifs_info *c, int lnum) · 196 unmodified lines | ||
| 197 | 197 | */ |
| 198 | 198 | static inline int ubifs_idx_node_sz(const struct ubifs_info *c, int child_cnt) |
| 199 | 199 | { |
| 200 | − return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len) * child_cnt; | |
| 200 | + return UBIFS_IDX_NODE_SZ + (UBIFS_BRANCH_SZ + c->key_len + c->hash_len) | |
| 201 | + * child_cnt; | |
| 201 | 202 | } |
| 202 | 203 | |
| 203 | 204 | /** |
| @@ -212,7 +213,7 @@ struct ubifs_branch *ubifs_idx_branch(const struct ubifs_info *c, · 8 unmodified lines | ||
| 212 | 213 | int bnum) |
| 213 | 214 | { |
| 214 | 215 | return (struct ubifs_branch *)((void *)idx->branches + |
| 215 | − (UBIFS_BRANCH_SZ + c->key_len) * bnum); | |
| 216 | + (UBIFS_BRANCH_SZ + c->key_len + c->hash_len) * bnum); | |
| 216 | 217 | } |
| 217 | 218 | |
| 218 | 219 | /** |
| @@ -212,7 +212,10 @@ static int write_rcvrd_mst_node(struct ubifs_info *c, · 211 unmodified lines | ||
| 212 | 212 | save_flags = mst->flags; |
| 213 | 213 | mst->flags |= cpu_to_le32(UBIFS_MST_RCVRY); |
| 214 | 214 | |
| 215 | − ubifs_prepare_node(c, mst, UBIFS_MST_NODE_SZ, 1); | |
| 215 | + err = ubifs_prepare_node_hmac(c, mst, UBIFS_MST_NODE_SZ, | |
| 216 | + offsetof(struct ubifs_mst_node, hmac), 1); | |
| 217 | + if (err) | |
| 218 | + goto out; | |
| 216 | 219 | err = ubifs_leb_change(c, lnum, mst, sz); |
| 217 | 220 | if (err) |
| 218 | 221 | goto out; |
| @@ -264,9 +267,7 @@ int ubifs_recover_master_node(struct ubifs_info *c) · 45 unmodified lines | ||
| 264 | 267 | offs2 = (void *)mst2 - buf2; |
| 265 | 268 | if (offs1 == offs2) { |
| 266 | 269 | /* Same offset, so must be the same */ |
| 267 | − if (memcmp((void *)mst1 + UBIFS_CH_SZ, | |
| 268 | − (void *)mst2 + UBIFS_CH_SZ, | |
| 269 | − UBIFS_MST_NODE_SZ - UBIFS_CH_SZ)) | |
| 270 | + if (ubifs_compare_master_node(c, mst1, mst2)) | |
| 270 | 271 | goto out_err; |
| 271 | 272 | mst = mst1; |
| 272 | 273 | } else if (offs2 + sz == offs1) { |
| @@ -1461,16 +1462,82 @@ out: · 1188 unmodified lines | ||
| 1461 | 1462 | return err; |
| 1462 | 1463 | } |
| 1463 | 1464 | |
| 1465 | +/** | |
| 1466 | + * inode_fix_size - fix inode size | |
| 1467 | + * @c: UBIFS file-system description object | |
| 1468 | + * @e: inode size information for recovery | |
| 1469 | + */ | |
| 1470 | +static int inode_fix_size(struct ubifs_info *c, struct size_entry *e) | |
| 1471 | +{ | |
| 1472 | + struct inode *inode; | |
| 1473 | + struct ubifs_inode *ui; | |
| 1474 | + int err; | |
| 1475 | + | |
| 1476 | + if (c->ro_mount) | |
| 1477 | + ubifs_assert(c, !e->inode); | |
| 1478 | + | |
| 1479 | + if (e->inode) { | |
| 1480 | + /* Remounting rw, pick up inode we stored earlier */ | |
| 1481 | + inode = e->inode; | |
| 1482 | + } else { | |
| 1483 | + inode = ubifs_iget(c->vfs_sb, e->inum); | |
| 1484 | + if (IS_ERR(inode)) | |
| 1485 | + return PTR_ERR(inode); | |
| 1486 | + | |
| 1487 | + if (inode->i_size >= e->d_size) { | |
| 1488 | + /* | |
| 1489 | + * The original inode in the index already has a size | |
| 1490 | + * big enough, nothing to do | |
| 1491 | + */ | |
| 1492 | + iput(inode); | |
| 1493 | + return 0; | |
| 1494 | + } | |
| 1495 | + | |
| 1496 | + dbg_rcvry("ino %lu size %lld -> %lld", | |
| 1497 | + (unsigned long)e->inum, | |
| 1498 | + inode->i_size, e->d_size); | |
| 1499 | + | |
| 1500 | + ui = ubifs_inode(inode); | |
| 1501 | + | |
| 1502 | + inode->i_size = e->d_size; | |
| 1503 | + ui->ui_size = e->d_size; | |
| 1504 | + ui->synced_i_size = e->d_size; | |
| 1505 | + | |
| 1506 | + e->inode = inode; | |
| 1507 | + } | |
| 1508 | + | |
| 1509 | + /* | |
| 1510 | + * In readonly mode just keep the inode pinned in memory until we go | |
| 1511 | + * readwrite. In readwrite mode write the inode to the journal with the | |
| 1512 | + * fixed size. | |
| 1513 | + */ | |
| 1514 | + if (c->ro_mount) | |
| 1515 | + return 0; | |
| 1516 | + | |
| 1517 | + err = ubifs_jnl_write_inode(c, inode); | |
| 1518 | + | |
| 1519 | + iput(inode); | |
| 1520 | + | |
| 1521 | + if (err) | |
| 1522 | + return err; | |
| 1523 | + | |
| 1524 | + rb_erase(&e->rb, &c->size_tree); | |
| 1525 | + kfree(e); | |
| 1526 | + | |
| 1527 | + return 0; | |
| 1528 | +} | |
| 1529 | + | |
| 1464 | 1530 | /** |
| 1465 | 1531 | * ubifs_recover_size - recover inode size. |
| 1466 | 1532 | * @c: UBIFS file-system description object |
| 1533 | + * @in_place: If true, do a in-place size fixup | |
| 1467 | 1534 | * |
| 1468 | 1535 | * This function attempts to fix inode size discrepancies identified by the |
| 1469 | 1536 | * 'ubifs_recover_size_accum()' function. |
| 1470 | 1537 | * |
| 1471 | 1538 | * This functions returns %0 on success and a negative error code on failure. |
| 1472 | 1539 | */ |
| 1473 | −int ubifs_recover_size(struct ubifs_info *c) | |
| 1540 | +int ubifs_recover_size(struct ubifs_info *c, bool in_place) | |
| 1474 | 1541 | { |
| 1475 | 1542 | struct rb_node *this = rb_first(&c->size_tree); |
| 1476 | 1543 | |
| @@ -1479,6 +1546,9 @@ int ubifs_recover_size(struct ubifs_info *c) · 2 unmodified lines | ||
| 1479 | 1546 | int err; |
| 1480 | 1547 | |
| 1481 | 1548 | e = rb_entry(this, struct size_entry, rb); |
| 1549 | + | |
| 1550 | + this = rb_next(this); | |
| 1551 | + | |
| 1482 | 1552 | if (!e->exists) { |
| 1483 | 1553 | union ubifs_key key; |
| 1484 | 1554 | |
| @@ -1502,40 +1572,26 @@ int ubifs_recover_size(struct ubifs_info *c) · 17 unmodified lines | ||
| 1502 | 1572 | } |
| 1503 | 1573 | |
| 1504 | 1574 | if (e->exists && e->i_size < e->d_size) { |
| 1505 | − if (c->ro_mount) { | |
| 1506 | − /* Fix the inode size and pin it in memory */ | |
| 1507 | − struct inode *inode; | |
| 1508 | − struct ubifs_inode *ui; | |
| 1509 | − | |
| 1510 | − ubifs_assert(c, !e->inode); | |
| 1511 | − | |
| 1512 | − inode = ubifs_iget(c->vfs_sb, e->inum); | |
| 1513 | − if (IS_ERR(inode)) | |
| 1514 | − return PTR_ERR(inode); | |
| 1515 | − | |
| 1516 | − ui = ubifs_inode(inode); | |
| 1517 | − if (inode->i_size < e->d_size) { | |
| 1518 | − dbg_rcvry("ino %lu size %lld -> %lld", | |
| 1519 | − (unsigned long)e->inum, | |
| 1520 | − inode->i_size, e->d_size); | |
| 1521 | − inode->i_size = e->d_size; | |
| 1522 | − ui->ui_size = e->d_size; | |
| 1523 | − ui->synced_i_size = e->d_size; | |
| 1524 | − e->inode = inode; | |
| 1525 | − this = rb_next(this); | |
| 1526 | − continue; | |
| 1527 | − } | |
| 1528 | − iput(inode); | |
| 1529 | − } else { | |
| 1530 | − /* Fix the size in place */ | |
| 1575 | + ubifs_assert(c, !(c->ro_mount && in_place)); | |
| 1576 | + | |
| 1577 | + /* | |
| 1578 | + * We found data that is outside the found inode size, | |
| 1579 | + * fixup the inode size | |
| 1580 | + */ | |
| 1581 | + | |
| 1582 | + if (in_place) { | |
| 1531 | 1583 | err = fix_size_in_place(c, e); |
| 1532 | 1584 | if (err) |
| 1533 | 1585 | return err; |
| 1534 | 1586 | iput(e->inode); |
| 1587 | + } else { | |
| 1588 | + err = inode_fix_size(c, e); | |
| 1589 | + if (err) | |
| 1590 | + return err; | |
| 1591 | + continue; | |
| 1535 | 1592 | } |
| 1536 | 1593 | } |
| 1537 | 1594 | |
| 1538 | − this = rb_next(this); | |
| 1539 | 1595 | rb_erase(&e->rb, &c->size_tree); |
| 1540 | 1596 | kfree(e); |
| 1541 | 1597 | } |
| @@ -34,6 +34,8 @@ · 33 unmodified lines | ||
| 34 | 34 | |
| 35 | 35 | #include "ubifs.h" |
| 36 | 36 | #include <linux/list_sort.h> |
| 37 | +#include <crypto/hash.h> | |
| 38 | +#include <crypto/algapi.h> | |
| 37 | 39 | |
| 38 | 40 | /** |
| 39 | 41 | * struct replay_entry - replay list entry. |
| @@ -56,6 +58,7 @@ struct replay_entry { · 16 unmodified lines | ||
| 56 | 58 | int lnum; |
| 57 | 59 | int offs; |
| 58 | 60 | int len; |
| 61 | + u8 hash[UBIFS_HASH_ARR_SZ]; | |
| 59 | 62 | unsigned int deletion:1; |
| 60 | 63 | unsigned long long sqnum; |
| 61 | 64 | struct list_head list; |
| @@ -228,7 +231,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r) · 166 unmodified lines | ||
| 228 | 231 | err = ubifs_tnc_remove_nm(c, &r->key, &r->nm); |
| 229 | 232 | else |
| 230 | 233 | err = ubifs_tnc_add_nm(c, &r->key, r->lnum, r->offs, |
| 231 | − r->len, &r->nm); | |
| 234 | + r->len, r->hash, &r->nm); | |
| 232 | 235 | } else { |
| 233 | 236 | if (r->deletion) |
| 234 | 237 | switch (key_type(c, &r->key)) { |
| @@ -248,7 +251,7 @@ static int apply_replay_entry(struct ubifs_info *c, struct replay_entry *r) · 13 unmodified lines | ||
| 248 | 251 | } |
| 249 | 252 | else |
| 250 | 253 | err = ubifs_tnc_add(c, &r->key, r->lnum, r->offs, |
| 251 | − r->len); | |
| 254 | + r->len, r->hash); | |
| 252 | 255 | if (err) |
| 253 | 256 | return err; |
| 254 | 257 | |
| @@ -352,9 +355,9 @@ static void destroy_replay_list(struct ubifs_info *c) · 97 unmodified lines | ||
| 352 | 355 | * in case of success and a negative error code in case of failure. |
| 353 | 356 | */ |
| 354 | 357 | static int insert_node(struct ubifs_info *c, int lnum, int offs, int len, |
| 355 | − union ubifs_key *key, unsigned long long sqnum, | |
| 356 | − int deletion, int *used, loff_t old_size, | |
| 357 | − loff_t new_size) | |
| 358 | + const u8 *hash, union ubifs_key *key, | |
| 359 | + unsigned long long sqnum, int deletion, int *used, | |
| 360 | + loff_t old_size, loff_t new_size) | |
| 358 | 361 | { |
| 359 | 362 | struct replay_entry *r; |
| 360 | 363 | |
| @@ -372,6 +375,7 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len, · 11 unmodified lines | ||
| 372 | 375 | r->lnum = lnum; |
| 373 | 376 | r->offs = offs; |
| 374 | 377 | r->len = len; |
| 378 | + ubifs_copy_hash(c, hash, r->hash); | |
| 375 | 379 | r->deletion = !!deletion; |
| 376 | 380 | r->sqnum = sqnum; |
| 377 | 381 | key_copy(c, key, &r->key); |
| @@ -400,8 +404,9 @@ static int insert_node(struct ubifs_info *c, int lnum, int offs, int len, · 22 unmodified lines | ||
| 400 | 404 | * negative error code in case of failure. |
| 401 | 405 | */ |
| 402 | 406 | static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len, |
| 403 | − union ubifs_key *key, const char *name, int nlen, | |
| 404 | − unsigned long long sqnum, int deletion, int *used) | |
| 407 | + const u8 *hash, union ubifs_key *key, | |
| 408 | + const char *name, int nlen, unsigned long long sqnum, | |
| 409 | + int deletion, int *used) | |
| 405 | 410 | { |
| 406 | 411 | struct replay_entry *r; |
| 407 | 412 | char *nbuf; |
| @@ -425,6 +430,7 @@ static int insert_dent(struct ubifs_info *c, int lnum, int offs, int len, · 17 unmodified lines | ||
| 425 | 430 | r->lnum = lnum; |
| 426 | 431 | r->offs = offs; |
| 427 | 432 | r->len = len; |
| 433 | + ubifs_copy_hash(c, hash, r->hash); | |
| 428 | 434 | r->deletion = !!deletion; |
| 429 | 435 | r->sqnum = sqnum; |
| 430 | 436 | key_copy(c, key, &r->key); |
| @@ -527,6 +533,105 @@ static int is_last_bud(struct ubifs_info *c, struct ubifs_bud *bud) · 96 unmodified lines | ||
| 527 | 533 | return data == 0xFFFFFFFF; |
| 528 | 534 | } |
| 529 | 535 | |
| 536 | +/** | |
| 537 | + * authenticate_sleb - authenticate one scan LEB | |
| 538 | + * @c: UBIFS file-system description object | |
| 539 | + * @sleb: the scan LEB to authenticate | |
| 540 | + * @log_hash: | |
| 541 | + * @is_last: if true, this is is the last LEB | |
| 542 | + * | |
| 543 | + * This function iterates over the buds of a single LEB authenticating all buds | |
| 544 | + * with the authentication nodes on this LEB. Authentication nodes are written | |
| 545 | + * after some buds and contain a HMAC covering the authentication node itself | |
| 546 | + * and the buds between the last authentication node and the current | |
| 547 | + * authentication node. It can happen that the last buds cannot be authenticated | |
| 548 | + * because a powercut happened when some nodes were written but not the | |
| 549 | + * corresponding authentication node. This function returns the number of nodes | |
| 550 | + * that could be authenticated or a negative error code. | |
| 551 | + */ | |
| 552 | +static int authenticate_sleb(struct ubifs_info *c, struct ubifs_scan_leb *sleb, | |
| 553 | + struct shash_desc *log_hash, int is_last) | |
| 554 | +{ | |
| 555 | + int n_not_auth = 0; | |
| 556 | + struct ubifs_scan_node *snod; | |
| 557 | + int n_nodes = 0; | |
| 558 | + int err; | |
| 559 | + u8 *hash, *hmac; | |
| 560 | + | |
| 561 | + if (!ubifs_authenticated(c)) | |
| 562 | + return sleb->nodes_cnt; | |
| 563 | + | |
| 564 | + hash = kmalloc(crypto_shash_descsize(c->hash_tfm), GFP_NOFS); | |
| 565 | + hmac = kmalloc(c->hmac_desc_len, GFP_NOFS); | |
| 566 | + if (!hash || !hmac) { | |
| 567 | + err = -ENOMEM; | |
| 568 | + goto out; | |
| 569 | + } | |
| 570 | + | |
| 571 | + list_for_each_entry(snod, &sleb->nodes, list) { | |
| 572 | + | |
| 573 | + n_nodes++; | |
| 574 | + | |
| 575 | + if (snod->type == UBIFS_AUTH_NODE) { | |
| 576 | + struct ubifs_auth_node *auth = snod->node; | |
| 577 | + SHASH_DESC_ON_STACK(hash_desc, c->hash_tfm); | |
| 578 | + SHASH_DESC_ON_STACK(hmac_desc, c->hmac_tfm); | |
| 579 | + | |
| 580 | + hash_desc->tfm = c->hash_tfm; | |
| 581 | + hash_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | |
| 582 | + | |
| 583 | + ubifs_shash_copy_state(c, log_hash, hash_desc); | |
| 584 | + err = crypto_shash_final(hash_desc, hash); | |
| 585 | + if (err) | |
| 586 | + goto out; | |
| 587 | + | |
| 588 | + hmac_desc->tfm = c->hmac_tfm; | |
| 589 | + hmac_desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP; | |
| 590 | + err = crypto_shash_digest(hmac_desc, hash, c->hash_len, | |
| 591 | + hmac); | |
| 592 | + if (err) | |
| 593 | + goto out; | |
| 594 | + | |
| 595 | + err = ubifs_check_hmac(c, auth->hmac, hmac); | |
| 596 | + if (err) { | |
| 597 | + err = -EPERM; | |
| 598 | + goto out; | |
| 599 | + } | |
| 600 | + n_not_auth = 0; | |
| 601 | + } else { | |
| 602 | + err = crypto_shash_update(log_hash, snod->node, | |
| 603 | + snod->len); | |
| 604 | + if (err) | |
| 605 | + goto out; | |
| 606 | + n_not_auth++; | |
| 607 | + } | |
| 608 | + } | |
| 609 | + | |
| 610 | + /* | |
| 611 | + * A powercut can happen when some nodes were written, but not yet | |
| 612 | + * the corresponding authentication node. This may only happen on | |
| 613 | + * the last bud though. | |
| 614 | + */ | |
| 615 | + if (n_not_auth) { | |
| 616 | + if (is_last) { | |
| 617 | + dbg_mnt("%d unauthenticated nodes found on LEB %d, Ignoring them", | |
| 618 | + n_not_auth, sleb->lnum); | |
| 619 | + err = 0; | |
| 620 | + } else { | |
| 621 | + dbg_mnt("%d unauthenticated nodes found on non-last LEB %d", | |
| 622 | + n_not_auth, sleb->lnum); | |
| 623 | + err = -EPERM; | |
| 624 | + } | |
| 625 | + } else { | |
| 626 | + err = 0; | |
| 627 | + } | |
| 628 | +out: | |
| 629 | + kfree(hash); | |
| 630 | + kfree(hmac); | |
| 631 | + | |
| 632 | + return err ? err : n_nodes - n_not_auth; | |
| 633 | +} | |
| 634 | + | |
| 530 | 635 | /** |
| 531 | 636 | * replay_bud - replay a bud logical eraseblock. |
| 532 | 637 | * @c: UBIFS file-system description object |
| @@ -540,6 +645,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b) · 7 unmodified lines | ||
| 540 | 645 | { |
| 541 | 646 | int is_last = is_last_bud(c, b->bud); |
| 542 | 647 | int err = 0, used = 0, lnum = b->bud->lnum, offs = b->bud->start; |
| 648 | + int n_nodes, n = 0; | |
| 543 | 649 | struct ubifs_scan_leb *sleb; |
| 544 | 650 | struct ubifs_scan_node *snod; |
| 545 | 651 | |
| @@ -559,6 +665,15 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b) · 13 unmodified lines | ||
| 559 | 665 | if (IS_ERR(sleb)) |
| 560 | 666 | return PTR_ERR(sleb); |
| 561 | 667 | |
| 668 | + n_nodes = authenticate_sleb(c, sleb, b->bud->log_hash, is_last); | |
| 669 | + if (n_nodes < 0) { | |
| 670 | + err = n_nodes; | |
| 671 | + goto out; | |
| 672 | + } | |
| 673 | + | |
| 674 | + ubifs_shash_copy_state(c, b->bud->log_hash, | |
| 675 | + c->jheads[b->bud->jhead].log_hash); | |
| 676 | + | |
| 562 | 677 | /* |
| 563 | 678 | * The bud does not have to start from offset zero - the beginning of |
| 564 | 679 | * the 'lnum' LEB may contain previously committed data. One of the |
| @@ -582,6 +697,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b) · 17 unmodified lines | ||
| 582 | 697 | */ |
| 583 | 698 | |
| 584 | 699 | list_for_each_entry(snod, &sleb->nodes, list) { |
| 700 | + u8 hash[UBIFS_HASH_ARR_SZ]; | |
| 585 | 701 | int deletion = 0; |
| 586 | 702 | |
| 587 | 703 | cond_resched(); |
| @@ -591,6 +707,8 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b) · 3 unmodified lines | ||
| 591 | 707 | goto out_dump; |
| 592 | 708 | } |
| 593 | 709 | |
| 710 | + ubifs_node_calc_hash(c, snod->node, hash); | |
| 711 | + | |
| 594 | 712 | if (snod->sqnum > c->max_sqnum) |
| 595 | 713 | c->max_sqnum = snod->sqnum; |
| 596 | 714 | |
| @@ -602,7 +720,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b) · 5 unmodified lines | ||
| 602 | 720 | |
| 603 | 721 | if (le32_to_cpu(ino->nlink) == 0) |
| 604 | 722 | deletion = 1; |
| 605 | − err = insert_node(c, lnum, snod->offs, snod->len, | |
| 723 | + err = insert_node(c, lnum, snod->offs, snod->len, hash, | |
| 606 | 724 | &snod->key, snod->sqnum, deletion, |
| 607 | 725 | &used, 0, new_size); |
| 608 | 726 | break; |
| @@ -614,7 +732,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b) · 5 unmodified lines | ||
| 614 | 732 | key_block(c, &snod->key) * |
| 615 | 733 | UBIFS_BLOCK_SIZE; |
| 616 | 734 | |
| 617 | − err = insert_node(c, lnum, snod->offs, snod->len, | |
| 735 | + err = insert_node(c, lnum, snod->offs, snod->len, hash, | |
| 618 | 736 | &snod->key, snod->sqnum, deletion, |
| 619 | 737 | &used, 0, new_size); |
| 620 | 738 | break; |
| @@ -628,7 +746,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b) · 7 unmodified lines | ||
| 628 | 746 | if (err) |
| 629 | 747 | goto out_dump; |
| 630 | 748 | |
| 631 | − err = insert_dent(c, lnum, snod->offs, snod->len, | |
| 749 | + err = insert_dent(c, lnum, snod->offs, snod->len, hash, | |
| 632 | 750 | &snod->key, dent->name, |
| 633 | 751 | le16_to_cpu(dent->nlen), snod->sqnum, |
| 634 | 752 | !le64_to_cpu(dent->inum), &used); |
| @@ -654,11 +772,13 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b) · 19 unmodified lines | ||
| 654 | 772 | * functions which expect nodes to have keys. |
| 655 | 773 | */ |
| 656 | 774 | trun_key_init(c, &key, le32_to_cpu(trun->inum)); |
| 657 | − err = insert_node(c, lnum, snod->offs, snod->len, | |
| 775 | + err = insert_node(c, lnum, snod->offs, snod->len, hash, | |
| 658 | 776 | &key, snod->sqnum, 1, &used, |
| 659 | 777 | old_size, new_size); |
| 660 | 778 | break; |
| 661 | 779 | } |
| 780 | + case UBIFS_AUTH_NODE: | |
| 781 | + break; | |
| 662 | 782 | default: |
| 663 | 783 | ubifs_err(c, "unexpected node type %d in bud LEB %d:%d", |
| 664 | 784 | snod->type, lnum, snod->offs); |
| @@ -667,6 +787,10 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b) · 2 unmodified lines | ||
| 667 | 787 | } |
| 668 | 788 | if (err) |
| 669 | 789 | goto out; |
| 790 | + | |
| 791 | + n++; | |
| 792 | + if (n == n_nodes) | |
| 793 | + break; | |
| 670 | 794 | } |
| 671 | 795 | |
| 672 | 796 | ubifs_assert(c, ubifs_search_bud(c, lnum)); |
| @@ -745,6 +869,7 @@ static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead, · 72 unmodified lines | ||
| 745 | 869 | { |
| 746 | 870 | struct ubifs_bud *bud; |
| 747 | 871 | struct bud_entry *b; |
| 872 | + int err; | |
| 748 | 873 | |
| 749 | 874 | dbg_mnt("add replay bud LEB %d:%d, head %d", lnum, offs, jhead); |
| 750 | 875 | |
| @@ -754,13 +879,21 @@ static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead, · 3 unmodified lines | ||
| 754 | 879 | |
| 755 | 880 | b = kmalloc(sizeof(struct bud_entry), GFP_KERNEL); |
| 756 | 881 | if (!b) { |
| 757 | − kfree(bud); | |
| 758 | − return -ENOMEM; | |
| 882 | + err = -ENOMEM; | |
| 883 | + goto out; | |
| 759 | 884 | } |
| 760 | 885 | |
| 761 | 886 | bud->lnum = lnum; |
| 762 | 887 | bud->start = offs; |
| 763 | 888 | bud->jhead = jhead; |
| 889 | + bud->log_hash = ubifs_hash_get_desc(c); | |
| 890 | + if (IS_ERR(bud->log_hash)) { | |
| 891 | + err = PTR_ERR(bud->log_hash); | |
| 892 | + goto out; | |
| 893 | + } | |
| 894 | + | |
| 895 | + ubifs_shash_copy_state(c, c->log_hash, bud->log_hash); | |
| 896 | + | |
| 764 | 897 | ubifs_add_bud(c, bud); |
| 765 | 898 | |
| 766 | 899 | b->bud = bud; |
| @@ -768,6 +901,11 @@ static int add_replay_bud(struct ubifs_info *c, int lnum, int offs, int jhead, · 1 unmodified line | ||
| 768 | 901 | list_add_tail(&b->list, &c->replay_buds); |
| 769 | 902 | |
| 770 | 903 | return 0; |
| 904 | +out: | |
| 905 | + kfree(bud); | |
| 906 | + kfree(b); | |
| 907 | + | |
| 908 | + return err; | |
| 771 | 909 | } |
| 772 | 910 | |
| 773 | 911 | /** |
| @@ -873,6 +1011,14 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf) · 99 unmodified lines | ||
| 873 | 1011 | |
| 874 | 1012 | c->cs_sqnum = le64_to_cpu(node->ch.sqnum); |
| 875 | 1013 | dbg_mnt("commit start sqnum %llu", c->cs_sqnum); |
| 1014 | + | |
| 1015 | + err = ubifs_shash_init(c, c->log_hash); | |
| 1016 | + if (err) | |
| 1017 | + goto out; | |
| 1018 | + | |
| 1019 | + err = ubifs_shash_update(c, c->log_hash, node, UBIFS_CS_NODE_SZ); | |
| 1020 | + if (err < 0) | |
| 1021 | + goto out; | |
| 876 | 1022 | } |
| 877 | 1023 | |
| 878 | 1024 | if (snod->sqnum < c->cs_sqnum) { |
| @@ -920,6 +1066,11 @@ static int replay_log_leb(struct ubifs_info *c, int lnum, int offs, void *sbuf) · 41 unmodified lines | ||
| 920 | 1066 | if (err) |
| 921 | 1067 | goto out_dump; |
| 922 | 1068 | |
| 1069 | + err = ubifs_shash_update(c, c->log_hash, ref, | |
| 1070 | + UBIFS_REF_NODE_SZ); | |
| 1071 | + if (err) | |
| 1072 | + goto out; | |
| 1073 | + | |
| 923 | 1074 | err = add_replay_bud(c, le32_to_cpu(ref->lnum), |
| 924 | 1075 | le32_to_cpu(ref->offs), |
| 925 | 1076 | le32_to_cpu(ref->jhead), |
| @@ -82,10 +82,13 @@ static int create_default_filesystem(struct ubifs_info *c) · 81 unmodified lines | ||
| 82 | 82 | int err, tmp, jnl_lebs, log_lebs, max_buds, main_lebs, main_first; |
| 83 | 83 | int lpt_lebs, lpt_first, orph_lebs, big_lpt, ino_waste, sup_flags = 0; |
| 84 | 84 | int min_leb_cnt = UBIFS_MIN_LEB_CNT; |
| 85 | + int idx_node_size; | |
| 85 | 86 | long long tmp64, main_bytes; |
| 86 | 87 | __le64 tmp_le64; |
| 87 | 88 | __le32 tmp_le32; |
| 88 | 89 | struct timespec64 ts; |
| 90 | + u8 hash[UBIFS_HASH_ARR_SZ]; | |
| 91 | + u8 hash_lpt[UBIFS_HASH_ARR_SZ]; | |
| 89 | 92 | |
| 90 | 93 | /* Some functions called from here depend on the @c->key_len filed */ |
| 91 | 94 | c->key_len = UBIFS_SK_LEN; |
| @@ -147,7 +150,7 @@ static int create_default_filesystem(struct ubifs_info *c) · 55 unmodified lines | ||
| 147 | 150 | c->lsave_cnt = DEFAULT_LSAVE_CNT; |
| 148 | 151 | c->max_leb_cnt = c->leb_cnt; |
| 149 | 152 | err = ubifs_create_dflt_lpt(c, &main_lebs, lpt_first, &lpt_lebs, |
| 150 | − &big_lpt); | |
| 153 | + &big_lpt, hash_lpt); | |
| 151 | 154 | if (err) |
| 152 | 155 | return err; |
| 153 | 156 | |
| @@ -156,17 +159,35 @@ static int create_default_filesystem(struct ubifs_info *c) · 2 unmodified lines | ||
| 156 | 159 | |
| 157 | 160 | main_first = c->leb_cnt - main_lebs; |
| 158 | 161 | |
| 162 | + sup = kzalloc(ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size), GFP_KERNEL); | |
| 163 | + mst = kzalloc(c->mst_node_alsz, GFP_KERNEL); | |
| 164 | + idx_node_size = ubifs_idx_node_sz(c, 1); | |
| 165 | + idx = kzalloc(ALIGN(tmp, c->min_io_size), GFP_KERNEL); | |
| 166 | + ino = kzalloc(ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size), GFP_KERNEL); | |
| 167 | + cs = kzalloc(ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size), GFP_KERNEL); | |
| 168 | + | |
| 169 | + if (!sup || !mst || !idx || !ino || !cs) { | |
| 170 | + err = -ENOMEM; | |
| 171 | + goto out; | |
| 172 | + } | |
| 173 | + | |
| 159 | 174 | /* Create default superblock */ |
| 160 | − tmp = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size); | |
| 161 | − sup = kzalloc(tmp, GFP_KERNEL); | |
| 162 | − if (!sup) | |
| 163 | − return -ENOMEM; | |
| 164 | 175 | |
| 165 | 176 | tmp64 = (long long)max_buds * c->leb_size; |
| 166 | 177 | if (big_lpt) |
| 167 | 178 | sup_flags |= UBIFS_FLG_BIGLPT; |
| 168 | 179 | sup_flags |= UBIFS_FLG_DOUBLE_HASH; |
| 169 | 180 | |
| 181 | + if (ubifs_authenticated(c)) { | |
| 182 | + sup_flags |= UBIFS_FLG_AUTHENTICATION; | |
| 183 | + sup->hash_algo = cpu_to_le16(c->auth_hash_algo); | |
| 184 | + err = ubifs_hmac_wkm(c, sup->hmac_wkm); | |
| 185 | + if (err) | |
| 186 | + goto out; | |
| 187 | + } else { | |
| 188 | + sup->hash_algo = 0xffff; | |
| 189 | + } | |
| 190 | + | |
| 170 | 191 | sup->ch.node_type = UBIFS_SB_NODE; |
| 171 | 192 | sup->key_hash = UBIFS_KEY_HASH_R5; |
| 172 | 193 | sup->flags = cpu_to_le32(sup_flags); |
| @@ -197,17 +218,9 @@ static int create_default_filesystem(struct ubifs_info *c) · 24 unmodified lines | ||
| 197 | 218 | sup->rp_size = cpu_to_le64(tmp64); |
| 198 | 219 | sup->ro_compat_version = cpu_to_le32(UBIFS_RO_COMPAT_VERSION); |
| 199 | 220 | |
| 200 | − err = ubifs_write_node(c, sup, UBIFS_SB_NODE_SZ, 0, 0); | |
| 201 | − kfree(sup); | |
| 202 | − if (err) | |
| 203 | − return err; | |
| 204 | − | |
| 205 | 221 | dbg_gen("default superblock created at LEB 0:0"); |
| 206 | 222 | |
| 207 | 223 | /* Create default master node */ |
| 208 | − mst = kzalloc(c->mst_node_alsz, GFP_KERNEL); | |
| 209 | − if (!mst) | |
| 210 | − return -ENOMEM; | |
| 211 | 224 | |
| 212 | 225 | mst->ch.node_type = UBIFS_MST_NODE; |
| 213 | 226 | mst->log_lnum = cpu_to_le32(UBIFS_LOG_LNUM); |
| @@ -233,6 +246,7 @@ static int create_default_filesystem(struct ubifs_info *c) · 19 unmodified lines | ||
| 233 | 246 | mst->empty_lebs = cpu_to_le32(main_lebs - 2); |
| 234 | 247 | mst->idx_lebs = cpu_to_le32(1); |
| 235 | 248 | mst->leb_cnt = cpu_to_le32(c->leb_cnt); |
| 249 | + ubifs_copy_hash(c, hash_lpt, mst->hash_lpt); | |
| 236 | 250 | |
| 237 | 251 | /* Calculate lprops statistics */ |
| 238 | 252 | tmp64 = main_bytes; |
| @@ -253,24 +267,9 @@ static int create_default_filesystem(struct ubifs_info *c) · 14 unmodified lines | ||
| 253 | 267 | |
| 254 | 268 | mst->total_used = cpu_to_le64(UBIFS_INO_NODE_SZ); |
| 255 | 269 | |
| 256 | − err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0); | |
| 257 | − if (err) { | |
| 258 | − kfree(mst); | |
| 259 | − return err; | |
| 260 | − } | |
| 261 | − err = ubifs_write_node(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1, | |
| 262 | − 0); | |
| 263 | − kfree(mst); | |
| 264 | − if (err) | |
| 265 | − return err; | |
| 266 | − | |
| 267 | 270 | dbg_gen("default master node created at LEB %d:0", UBIFS_MST_LNUM); |
| 268 | 271 | |
| 269 | 272 | /* Create the root indexing node */ |
| 270 | − tmp = ubifs_idx_node_sz(c, 1); | |
| 271 | − idx = kzalloc(ALIGN(tmp, c->min_io_size), GFP_KERNEL); | |
| 272 | − if (!idx) | |
| 273 | − return -ENOMEM; | |
| 274 | 273 | |
| 275 | 274 | c->key_fmt = UBIFS_SIMPLE_KEY_FMT; |
| 276 | 275 | c->key_hash = key_r5_hash; |
| @@ -282,19 +281,11 @@ static int create_default_filesystem(struct ubifs_info *c) · 5 unmodified lines | ||
| 282 | 281 | key_write_idx(c, &key, &br->key); |
| 283 | 282 | br->lnum = cpu_to_le32(main_first + DEFAULT_DATA_LEB); |
| 284 | 283 | br->len = cpu_to_le32(UBIFS_INO_NODE_SZ); |
| 285 | − err = ubifs_write_node(c, idx, tmp, main_first + DEFAULT_IDX_LEB, 0); | |
| 286 | − kfree(idx); | |
| 287 | − if (err) | |
| 288 | − return err; | |
| 289 | 284 | |
| 290 | 285 | dbg_gen("default root indexing node created LEB %d:0", |
| 291 | 286 | main_first + DEFAULT_IDX_LEB); |
| 292 | 287 | |
| 293 | 288 | /* Create default root inode */ |
| 294 | − tmp = ALIGN(UBIFS_INO_NODE_SZ, c->min_io_size); | |
| 295 | − ino = kzalloc(tmp, GFP_KERNEL); | |
| 296 | − if (!ino) | |
| 297 | − return -ENOMEM; | |
| 298 | 289 | |
| 299 | 290 | ino_key_init_flash(c, &ino->key, UBIFS_ROOT_INO); |
| 300 | 291 | ino->ch.node_type = UBIFS_INO_NODE; |
| @@ -317,12 +308,6 @@ static int create_default_filesystem(struct ubifs_info *c) · 16 unmodified lines | ||
| 317 | 308 | /* Set compression enabled by default */ |
| 318 | 309 | ino->flags = cpu_to_le32(UBIFS_COMPR_FL); |
| 319 | 310 | |
| 320 | − err = ubifs_write_node(c, ino, UBIFS_INO_NODE_SZ, | |
| 321 | − main_first + DEFAULT_DATA_LEB, 0); | |
| 322 | − kfree(ino); | |
| 323 | − if (err) | |
| 324 | − return err; | |
| 325 | − | |
| 326 | 311 | dbg_gen("root inode created at LEB %d:0", |
| 327 | 312 | main_first + DEFAULT_DATA_LEB); |
| 328 | 313 | |
| @@ -331,19 +316,54 @@ static int create_default_filesystem(struct ubifs_info *c) · 2 unmodified lines | ||
| 331 | 316 | * always the case during normal file-system operation. Write a fake |
| 332 | 317 | * commit start node to the log. |
| 333 | 318 | */ |
| 334 | − tmp = ALIGN(UBIFS_CS_NODE_SZ, c->min_io_size); | |
| 335 | − cs = kzalloc(tmp, GFP_KERNEL); | |
| 336 | − if (!cs) | |
| 337 | − return -ENOMEM; | |
| 338 | 319 | |
| 339 | 320 | cs->ch.node_type = UBIFS_CS_NODE; |
| 321 | + | |
| 322 | + err = ubifs_write_node_hmac(c, sup, UBIFS_SB_NODE_SZ, 0, 0, | |
| 323 | + offsetof(struct ubifs_sb_node, hmac)); | |
| 324 | + if (err) | |
| 325 | + goto out; | |
| 326 | + | |
| 327 | + err = ubifs_write_node(c, ino, UBIFS_INO_NODE_SZ, | |
| 328 | + main_first + DEFAULT_DATA_LEB, 0); | |
| 329 | + if (err) | |
| 330 | + goto out; | |
| 331 | + | |
| 332 | + ubifs_node_calc_hash(c, ino, hash); | |
| 333 | + ubifs_copy_hash(c, hash, ubifs_branch_hash(c, br)); | |
| 334 | + | |
| 335 | + err = ubifs_write_node(c, idx, idx_node_size, main_first + DEFAULT_IDX_LEB, 0); | |
| 336 | + if (err) | |
| 337 | + goto out; | |
| 338 | + | |
| 339 | + ubifs_node_calc_hash(c, idx, hash); | |
| 340 | + ubifs_copy_hash(c, hash, mst->hash_root_idx); | |
| 341 | + | |
| 342 | + err = ubifs_write_node_hmac(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM, 0, | |
| 343 | + offsetof(struct ubifs_mst_node, hmac)); | |
| 344 | + if (err) | |
| 345 | + goto out; | |
| 346 | + | |
| 347 | + err = ubifs_write_node_hmac(c, mst, UBIFS_MST_NODE_SZ, UBIFS_MST_LNUM + 1, | |
| 348 | + 0, offsetof(struct ubifs_mst_node, hmac)); | |
| 349 | + if (err) | |
| 350 | + goto out; | |
| 351 | + | |
| 340 | 352 | err = ubifs_write_node(c, cs, UBIFS_CS_NODE_SZ, UBIFS_LOG_LNUM, 0); |
| 341 | − kfree(cs); | |
| 342 | 353 | if (err) |
| 343 | − return err; | |
| 354 | + goto out; | |
| 344 | 355 | |
| 345 | 356 | ubifs_msg(c, "default file-system created"); |
| 346 | − return 0; | |
| 357 | + | |
| 358 | + err = 0; | |
| 359 | +out: | |
| 360 | + kfree(sup); | |
| 361 | + kfree(mst); | |
| 362 | + kfree(idx); | |
| 363 | + kfree(ino); | |
| 364 | + kfree(cs); | |
| 365 | + | |
| 366 | + return err; | |
| 347 | 367 | } |
| 348 | 368 | |
| 349 | 369 | /** |
| @@ -498,7 +518,7 @@ failed: · 148 unmodified lines | ||
| 498 | 518 | * code. Note, the user of this function is responsible of kfree()'ing the |
| 499 | 519 | * returned superblock buffer. |
| 500 | 520 | */ |
| 501 | −struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c) | |
| 521 | +static struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c) | |
| 502 | 522 | { |
| 503 | 523 | struct ubifs_sb_node *sup; |
| 504 | 524 | int err; |
| @@ -517,6 +537,65 @@ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c) · 12 unmodified lines | ||
| 517 | 537 | return sup; |
| 518 | 538 | } |
| 519 | 539 | |
| 540 | +static int authenticate_sb_node(struct ubifs_info *c, | |
| 541 | + const struct ubifs_sb_node *sup) | |
| 542 | +{ | |
| 543 | + unsigned int sup_flags = le32_to_cpu(sup->flags); | |
| 544 | + u8 hmac_wkm[UBIFS_HMAC_ARR_SZ]; | |
| 545 | + int authenticated = !!(sup_flags & UBIFS_FLG_AUTHENTICATION); | |
| 546 | + int hash_algo; | |
| 547 | + int err; | |
| 548 | + | |
| 549 | + if (c->authenticated && !authenticated) { | |
| 550 | + ubifs_err(c, "authenticated FS forced, but found FS without authentication"); | |
| 551 | + return -EINVAL; | |
| 552 | + } | |
| 553 | + | |
| 554 | + if (!c->authenticated && authenticated) { | |
| 555 | + ubifs_err(c, "authenticated FS found, but no key given"); | |
| 556 | + return -EINVAL; | |
| 557 | + } | |
| 558 | + | |
| 559 | + ubifs_msg(c, "Mounting in %sauthenticated mode", | |
| 560 | + c->authenticated ? "" : "un"); | |
| 561 | + | |
| 562 | + if (!c->authenticated) | |
| 563 | + return 0; | |
| 564 | + | |
| 565 | + if (!IS_ENABLED(CONFIG_UBIFS_FS_AUTHENTICATION)) | |
| 566 | + return -EOPNOTSUPP; | |
| 567 | + | |
| 568 | + hash_algo = le16_to_cpu(sup->hash_algo); | |
| 569 | + if (hash_algo >= HASH_ALGO__LAST) { | |
| 570 | + ubifs_err(c, "superblock uses unknown hash algo %d", | |
| 571 | + hash_algo); | |
| 572 | + return -EINVAL; | |
| 573 | + } | |
| 574 | + | |
| 575 | + if (strcmp(hash_algo_name[hash_algo], c->auth_hash_name)) { | |
| 576 | + ubifs_err(c, "This filesystem uses %s for hashing," | |
| 577 | + " but %s is specified", hash_algo_name[hash_algo], | |
| 578 | + c->auth_hash_name); | |
| 579 | + return -EINVAL; | |
| 580 | + } | |
| 581 | + | |
| 582 | + err = ubifs_hmac_wkm(c, hmac_wkm); | |
| 583 | + if (err) | |
| 584 | + return err; | |
| 585 | + | |
| 586 | + if (ubifs_check_hmac(c, hmac_wkm, sup->hmac_wkm)) { | |
| 587 | + ubifs_err(c, "provided key does not fit"); | |
| 588 | + return -ENOKEY; | |
| 589 | + } | |
| 590 | + | |
| 591 | + err = ubifs_node_verify_hmac(c, sup, sizeof(*sup), | |
| 592 | + offsetof(struct ubifs_sb_node, hmac)); | |
| 593 | + if (err) | |
| 594 | + ubifs_err(c, "Failed to authenticate superblock: %d", err); | |
| 595 | + | |
| 596 | + return err; | |
| 597 | +} | |
| 598 | + | |
| 520 | 599 | /** |
| 521 | 600 | * ubifs_write_sb_node - write superblock node. |
| 522 | 601 | * @c: UBIFS file-system description object |
| @@ -527,8 +606,13 @@ struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c) · 4 unmodified lines | ||
| 527 | 606 | int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup) |
| 528 | 607 | { |
| 529 | 608 | int len = ALIGN(UBIFS_SB_NODE_SZ, c->min_io_size); |
| 609 | + int err; | |
| 610 | + | |
| 611 | + err = ubifs_prepare_node_hmac(c, sup, UBIFS_SB_NODE_SZ, | |
| 612 | + offsetof(struct ubifs_sb_node, hmac), 1); | |
| 613 | + if (err) | |
| 614 | + return err; | |
| 530 | 615 | |
| 531 | − ubifs_prepare_node(c, sup, UBIFS_SB_NODE_SZ, 1); | |
| 532 | 616 | return ubifs_leb_change(c, UBIFS_SB_LNUM, sup, len); |
| 533 | 617 | } |
| 534 | 618 | |
| @@ -555,6 +639,8 @@ int ubifs_read_superblock(struct ubifs_info *c) · 20 unmodified lines | ||
| 555 | 639 | if (IS_ERR(sup)) |
| 556 | 640 | return PTR_ERR(sup); |
| 557 | 641 | |
| 642 | + c->sup_node = sup; | |
| 643 | + | |
| 558 | 644 | c->fmt_version = le32_to_cpu(sup->fmt_version); |
| 559 | 645 | c->ro_compat_version = le32_to_cpu(sup->ro_compat_version); |
| 560 | 646 | |
| @@ -603,7 +689,7 @@ int ubifs_read_superblock(struct ubifs_info *c) · 42 unmodified lines | ||
| 603 | 689 | c->key_hash = key_test_hash; |
| 604 | 690 | c->key_hash_type = UBIFS_KEY_HASH_TEST; |
| 605 | 691 | break; |
| 606 | − }; | |
| 692 | + } | |
| 607 | 693 | |
| 608 | 694 | c->key_fmt = sup->key_fmt; |
| 609 | 695 | |
| @@ -640,6 +726,10 @@ int ubifs_read_superblock(struct ubifs_info *c) · 30 unmodified lines | ||
| 640 | 726 | c->double_hash = !!(sup_flags & UBIFS_FLG_DOUBLE_HASH); |
| 641 | 727 | c->encrypted = !!(sup_flags & UBIFS_FLG_ENCRYPTION); |
| 642 | 728 | |
| 729 | + err = authenticate_sb_node(c, sup); | |
| 730 | + if (err) | |
| 731 | + goto out; | |
| 732 | + | |
| 643 | 733 | if ((sup_flags & ~UBIFS_FLG_MASK) != 0) { |
| 644 | 734 | ubifs_err(c, "Unknown feature flags found: %#x", |
| 645 | 735 | sup_flags & ~UBIFS_FLG_MASK); |
| @@ -686,7 +776,6 @@ int ubifs_read_superblock(struct ubifs_info *c) · 40 unmodified lines | ||
| 686 | 776 | |
| 687 | 777 | err = validate_sb(c, sup); |
| 688 | 778 | out: |
| 689 | − kfree(sup); | |
| 690 | 779 | return err; |
| 691 | 780 | } |
| 692 | 781 | |
| @@ -815,7 +904,7 @@ out: · 122 unmodified lines | ||
| 815 | 904 | int ubifs_fixup_free_space(struct ubifs_info *c) |
| 816 | 905 | { |
| 817 | 906 | int err; |
| 818 | − struct ubifs_sb_node *sup; | |
| 907 | + struct ubifs_sb_node *sup = c->sup_node; | |
| 819 | 908 | |
| 820 | 909 | ubifs_assert(c, c->space_fixup); |
| 821 | 910 | ubifs_assert(c, !c->ro_mount); |
| @@ -826,16 +915,11 @@ int ubifs_fixup_free_space(struct ubifs_info *c) · 4 unmodified lines | ||
| 826 | 915 | if (err) |
| 827 | 916 | return err; |
| 828 | 917 | |
| 829 | − sup = ubifs_read_sb_node(c); | |
| 830 | − if (IS_ERR(sup)) | |
| 831 | − return PTR_ERR(sup); | |
| 832 | − | |
| 833 | 918 | /* Free-space fixup is no longer required */ |
| 834 | 919 | c->space_fixup = 0; |
| 835 | 920 | sup->flags &= cpu_to_le32(~UBIFS_FLG_SPACE_FIXUP); |
| 836 | 921 | |
| 837 | 922 | err = ubifs_write_sb_node(c, sup); |
| 838 | − kfree(sup); | |
| 839 | 923 | if (err) |
| 840 | 924 | return err; |
| 841 | 925 | |
| @@ -846,7 +930,7 @@ int ubifs_fixup_free_space(struct ubifs_info *c) · 4 unmodified lines | ||
| 846 | 930 | int ubifs_enable_encryption(struct ubifs_info *c) |
| 847 | 931 | { |
| 848 | 932 | int err; |
| 849 | − struct ubifs_sb_node *sup; | |
| 933 | + struct ubifs_sb_node *sup = c->sup_node; | |
| 850 | 934 | |
| 851 | 935 | if (c->encrypted) |
| 852 | 936 | return 0; |
| @@ -859,16 +943,11 @@ int ubifs_enable_encryption(struct ubifs_info *c) · 6 unmodified lines | ||
| 859 | 943 | return -EINVAL; |
| 860 | 944 | } |
| 861 | 945 | |
| 862 | − sup = ubifs_read_sb_node(c); | |
| 863 | − if (IS_ERR(sup)) | |
| 864 | − return PTR_ERR(sup); | |
| 865 | − | |
| 866 | 946 | sup->flags |= cpu_to_le32(UBIFS_FLG_ENCRYPTION); |
| 867 | 947 | |
| 868 | 948 | err = ubifs_write_sb_node(c, sup); |
| 869 | 949 | if (!err) |
| 870 | 950 | c->encrypted = 1; |
| 871 | − kfree(sup); | |
| 872 | 951 | |
| 873 | 952 | return err; |
| 874 | 953 | } |
| @@ -579,6 +579,9 @@ static int init_constants_early(struct ubifs_info *c) · 578 unmodified lines | ||
| 579 | 579 | c->ranges[UBIFS_REF_NODE].len = UBIFS_REF_NODE_SZ; |
| 580 | 580 | c->ranges[UBIFS_TRUN_NODE].len = UBIFS_TRUN_NODE_SZ; |
| 581 | 581 | c->ranges[UBIFS_CS_NODE].len = UBIFS_CS_NODE_SZ; |
| 582 | + c->ranges[UBIFS_AUTH_NODE].min_len = UBIFS_AUTH_NODE_SZ; | |
| 583 | + c->ranges[UBIFS_AUTH_NODE].max_len = UBIFS_AUTH_NODE_SZ + | |
| 584 | + UBIFS_MAX_HMAC_LEN; | |
| 582 | 585 | |
| 583 | 586 | c->ranges[UBIFS_INO_NODE].min_len = UBIFS_INO_NODE_SZ; |
| 584 | 587 | c->ranges[UBIFS_INO_NODE].max_len = UBIFS_MAX_INO_NODE_SZ; |
| @@ -816,6 +819,9 @@ static int alloc_wbufs(struct ubifs_info *c) · 231 unmodified lines | ||
| 816 | 819 | c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback; |
| 817 | 820 | c->jheads[i].wbuf.jhead = i; |
| 818 | 821 | c->jheads[i].grouped = 1; |
| 822 | + c->jheads[i].log_hash = ubifs_hash_get_desc(c); | |
| 823 | + if (IS_ERR(c->jheads[i].log_hash)) | |
| 824 | + goto out; | |
| 819 | 825 | } |
| 820 | 826 | |
| 821 | 827 | /* |
| @@ -826,6 +832,12 @@ static int alloc_wbufs(struct ubifs_info *c) · 4 unmodified lines | ||
| 826 | 832 | c->jheads[GCHD].grouped = 0; |
| 827 | 833 | |
| 828 | 834 | return 0; |
| 835 | + | |
| 836 | +out: | |
| 837 | + while (i--) | |
| 838 | + kfree(c->jheads[i].log_hash); | |
| 839 | + | |
| 840 | + return err; | |
| 829 | 841 | } |
| 830 | 842 | |
| 831 | 843 | /** |
| @@ -840,6 +852,7 @@ static void free_wbufs(struct ubifs_info *c) · 8 unmodified lines | ||
| 840 | 852 | for (i = 0; i < c->jhead_cnt; i++) { |
| 841 | 853 | kfree(c->jheads[i].wbuf.buf); |
| 842 | 854 | kfree(c->jheads[i].wbuf.inodes); |
| 855 | + kfree(c->jheads[i].log_hash); | |
| 843 | 856 | } |
| 844 | 857 | kfree(c->jheads); |
| 845 | 858 | c->jheads = NULL; |
| @@ -924,6 +937,8 @@ static int check_volume_empty(struct ubifs_info *c) · 78 unmodified lines | ||
| 924 | 937 | * Opt_no_chk_data_crc: do not check CRCs when reading data nodes |
| 925 | 938 | * Opt_override_compr: override default compressor |
| 926 | 939 | * Opt_assert: set ubifs_assert() action |
| 940 | + * Opt_auth_key: The key name used for authentication | |
| 941 | + * Opt_auth_hash_name: The hash type used for authentication | |
| 927 | 942 | * Opt_err: just end of array marker |
| 928 | 943 | */ |
| 929 | 944 | enum { |
| @@ -935,6 +950,8 @@ enum { · 5 unmodified lines | ||
| 935 | 950 | Opt_no_chk_data_crc, |
| 936 | 951 | Opt_override_compr, |
| 937 | 952 | Opt_assert, |
| 953 | + Opt_auth_key, | |
| 954 | + Opt_auth_hash_name, | |
| 938 | 955 | Opt_ignore, |
| 939 | 956 | Opt_err, |
| 940 | 957 | }; |
| @@ -947,6 +964,8 @@ static const match_table_t tokens = { · 6 unmodified lines | ||
| 947 | 964 | {Opt_chk_data_crc, "chk_data_crc"}, |
| 948 | 965 | {Opt_no_chk_data_crc, "no_chk_data_crc"}, |
| 949 | 966 | {Opt_override_compr, "compr=%s"}, |
| 967 | + {Opt_auth_key, "auth_key=%s"}, | |
| 968 | + {Opt_auth_hash_name, "auth_hash_name=%s"}, | |
| 950 | 969 | {Opt_ignore, "ubi=%s"}, |
| 951 | 970 | {Opt_ignore, "vol=%s"}, |
| 952 | 971 | {Opt_assert, "assert=%s"}, |
| @@ -1070,6 +1089,16 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options, · 117 unmodified lines | ||
| 1070 | 1089 | kfree(act); |
| 1071 | 1090 | break; |
| 1072 | 1091 | } |
| 1092 | + case Opt_auth_key: | |
| 1093 | + c->auth_key_name = kstrdup(args[0].from, GFP_KERNEL); | |
| 1094 | + if (!c->auth_key_name) | |
| 1095 | + return -ENOMEM; | |
| 1096 | + break; | |
| 1097 | + case Opt_auth_hash_name: | |
| 1098 | + c->auth_hash_name = kstrdup(args[0].from, GFP_KERNEL); | |
| 1099 | + if (!c->auth_hash_name) | |
| 1100 | + return -ENOMEM; | |
| 1101 | + break; | |
| 1073 | 1102 | case Opt_ignore: |
| 1074 | 1103 | break; |
| 1075 | 1104 | default: |
| @@ -1249,6 +1278,19 @@ static int mount_ubifs(struct ubifs_info *c) · 173 unmodified lines | ||
| 1249 | 1278 | |
| 1250 | 1279 | c->mounting = 1; |
| 1251 | 1280 | |
| 1281 | + if (c->auth_key_name) { | |
| 1282 | + if (IS_ENABLED(CONFIG_UBIFS_FS_AUTHENTICATION)) { | |
| 1283 | + err = ubifs_init_authentication(c); | |
| 1284 | + if (err) | |
| 1285 | + goto out_free; | |
| 1286 | + } else { | |
| 1287 | + ubifs_err(c, "auth_key_name, but UBIFS is built without" | |
| 1288 | + " authentication support"); | |
| 1289 | + err = -EINVAL; | |
| 1290 | + goto out_free; | |
| 1291 | + } | |
| 1292 | + } | |
| 1293 | + | |
| 1252 | 1294 | err = ubifs_read_superblock(c); |
| 1253 | 1295 | if (err) |
| 1254 | 1296 | goto out_free; |
| @@ -1367,12 +1409,21 @@ static int mount_ubifs(struct ubifs_info *c) · 112 unmodified lines | ||
| 1367 | 1409 | } |
| 1368 | 1410 | |
| 1369 | 1411 | if (c->need_recovery) { |
| 1370 | − err = ubifs_recover_size(c); | |
| 1371 | − if (err) | |
| 1372 | − goto out_orphans; | |
| 1412 | + if (!ubifs_authenticated(c)) { | |
| 1413 | + err = ubifs_recover_size(c, true); | |
| 1414 | + if (err) | |
| 1415 | + goto out_orphans; | |
| 1416 | + } | |
| 1417 | + | |
| 1373 | 1418 | err = ubifs_rcvry_gc_commit(c); |
| 1374 | 1419 | if (err) |
| 1375 | 1420 | goto out_orphans; |
| 1421 | + | |
| 1422 | + if (ubifs_authenticated(c)) { | |
| 1423 | + err = ubifs_recover_size(c, false); | |
| 1424 | + if (err) | |
| 1425 | + goto out_orphans; | |
| 1426 | + } | |
| 1376 | 1427 | } else { |
| 1377 | 1428 | err = take_gc_lnum(c); |
| 1378 | 1429 | if (err) |
| @@ -1391,7 +1442,7 @@ static int mount_ubifs(struct ubifs_info *c) · 12 unmodified lines | ||
| 1391 | 1442 | if (err) |
| 1392 | 1443 | goto out_orphans; |
| 1393 | 1444 | } else if (c->need_recovery) { |
| 1394 | − err = ubifs_recover_size(c); | |
| 1445 | + err = ubifs_recover_size(c, false); | |
| 1395 | 1446 | if (err) |
| 1396 | 1447 | goto out_orphans; |
| 1397 | 1448 | } else { |
| @@ -1557,7 +1608,10 @@ static void ubifs_umount(struct ubifs_info *c) · 159 unmodified lines | ||
| 1557 | 1608 | free_wbufs(c); |
| 1558 | 1609 | free_orphans(c); |
| 1559 | 1610 | ubifs_lpt_free(c, 0); |
| 1611 | + ubifs_exit_authentication(c); | |
| 1560 | 1612 | |
| 1613 | + kfree(c->auth_key_name); | |
| 1614 | + kfree(c->auth_hash_name); | |
| 1561 | 1615 | kfree(c->cbuf); |
| 1562 | 1616 | kfree(c->rcvrd_mst_node); |
| 1563 | 1617 | kfree(c->mst_node); |
| @@ -1605,16 +1659,10 @@ static int ubifs_remount_rw(struct ubifs_info *c) · 41 unmodified lines | ||
| 1605 | 1659 | goto out; |
| 1606 | 1660 | |
| 1607 | 1661 | if (c->old_leb_cnt != c->leb_cnt) { |
| 1608 | − struct ubifs_sb_node *sup; | |
| 1662 | + struct ubifs_sb_node *sup = c->sup_node; | |
| 1609 | 1663 | |
| 1610 | − sup = ubifs_read_sb_node(c); | |
| 1611 | − if (IS_ERR(sup)) { | |
| 1612 | − err = PTR_ERR(sup); | |
| 1613 | − goto out; | |
| 1614 | − } | |
| 1615 | 1664 | sup->leb_cnt = cpu_to_le32(c->leb_cnt); |
| 1616 | 1665 | err = ubifs_write_sb_node(c, sup); |
| 1617 | − kfree(sup); | |
| 1618 | 1666 | if (err) |
| 1619 | 1667 | goto out; |
| 1620 | 1668 | } |
| @@ -1624,9 +1672,11 @@ static int ubifs_remount_rw(struct ubifs_info *c) · 3 unmodified lines | ||
| 1624 | 1672 | err = ubifs_write_rcvrd_mst_node(c); |
| 1625 | 1673 | if (err) |
| 1626 | 1674 | goto out; |
| 1627 | − err = ubifs_recover_size(c); | |
| 1628 | − if (err) | |
| 1629 | − goto out; | |
| 1675 | + if (!ubifs_authenticated(c)) { | |
| 1676 | + err = ubifs_recover_size(c, true); | |
| 1677 | + if (err) | |
| 1678 | + goto out; | |
| 1679 | + } | |
| 1630 | 1680 | err = ubifs_clean_lebs(c, c->sbuf); |
| 1631 | 1681 | if (err) |
| 1632 | 1682 | goto out; |
| @@ -1692,10 +1742,19 @@ static int ubifs_remount_rw(struct ubifs_info *c) · 59 unmodified lines | ||
| 1692 | 1742 | goto out; |
| 1693 | 1743 | } |
| 1694 | 1744 | |
| 1695 | − if (c->need_recovery) | |
| 1745 | + if (c->need_recovery) { | |
| 1696 | 1746 | err = ubifs_rcvry_gc_commit(c); |
| 1697 | − else | |
| 1747 | + if (err) | |
| 1748 | + goto out; | |
| 1749 | + | |
| 1750 | + if (ubifs_authenticated(c)) { | |
| 1751 | + err = ubifs_recover_size(c, false); | |
| 1752 | + if (err) | |
| 1753 | + goto out; | |
| 1754 | + } | |
| 1755 | + } else { | |
| 1698 | 1756 | err = ubifs_leb_unmap(c, c->gc_lnum); |
| 1757 | + } | |
| 1699 | 1758 | if (err) |
| 1700 | 1759 | goto out; |
| 1701 | 1760 | |
| @@ -35,7 +35,7 @@ · 34 unmodified lines | ||
| 35 | 35 | #include "ubifs.h" |
| 36 | 36 | |
| 37 | 37 | static int try_read_node(const struct ubifs_info *c, void *buf, int type, |
| 38 | − int len, int lnum, int offs); | |
| 38 | + struct ubifs_zbranch *zbr); | |
| 39 | 39 | static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key, |
| 40 | 40 | struct ubifs_zbranch *zbr, void *node); |
| 41 | 41 | |
| @@ -433,9 +433,7 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr, · 391 unmodified lines | ||
| 433 | 433 | * @c: UBIFS file-system description object |
| 434 | 434 | * @buf: buffer to read to |
| 435 | 435 | * @type: node type |
| 436 | − * @len: node length (not aligned) | |
| 437 | − * @lnum: LEB number of node to read | |
| 438 | − * @offs: offset of node to read | |
| 436 | + * @zbr: the zbranch describing the node to read | |
| 439 | 437 | * |
| 440 | 438 | * This function tries to read a node of known type and length, checks it and |
| 441 | 439 | * stores it in @buf. This function returns %1 if a node is present and %0 if |
| @@ -453,8 +451,11 @@ static int tnc_read_hashed_node(struct ubifs_info *c, struct ubifs_zbranch *zbr, · 11 unmodified lines | ||
| 453 | 451 | * journal nodes may potentially be corrupted, so checking is required. |
| 454 | 452 | */ |
| 455 | 453 | static int try_read_node(const struct ubifs_info *c, void *buf, int type, |
| 456 | − int len, int lnum, int offs) | |
| 454 | + struct ubifs_zbranch *zbr) | |
| 457 | 455 | { |
| 456 | + int len = zbr->len; | |
| 457 | + int lnum = zbr->lnum; | |
| 458 | + int offs = zbr->offs; | |
| 458 | 459 | int err, node_len; |
| 459 | 460 | struct ubifs_ch *ch = buf; |
| 460 | 461 | uint32_t crc, node_crc; |
| @@ -487,6 +488,12 @@ static int try_read_node(const struct ubifs_info *c, void *buf, int type, · 26 unmodified lines | ||
| 487 | 488 | if (crc != node_crc) |
| 488 | 489 | return 0; |
| 489 | 490 | |
| 491 | + err = ubifs_node_check_hash(c, buf, zbr->hash); | |
| 492 | + if (err) { | |
| 493 | + ubifs_bad_hash(c, buf, zbr->hash, lnum, offs); | |
| 494 | + return 0; | |
| 495 | + } | |
| 496 | + | |
| 490 | 497 | return 1; |
| 491 | 498 | } |
| 492 | 499 | |
| @@ -507,8 +514,7 @@ static int fallible_read_node(struct ubifs_info *c, const union ubifs_key *key, · 14 unmodified lines | ||
| 507 | 514 | |
| 508 | 515 | dbg_tnck(key, "LEB %d:%d, key ", zbr->lnum, zbr->offs); |
| 509 | 516 | |
| 510 | − ret = try_read_node(c, node, key_type(c, key), zbr->len, zbr->lnum, | |
| 511 | − zbr->offs); | |
| 517 | + ret = try_read_node(c, node, key_type(c, key), zbr); | |
| 512 | 518 | if (ret == 1) { |
| 513 | 519 | union ubifs_key node_key; |
| 514 | 520 | struct ubifs_dent_node *dent = node; |
| @@ -1713,6 +1719,12 @@ static int validate_data_node(struct ubifs_info *c, void *buf, · 1198 unmodified lines | ||
| 1713 | 1719 | goto out; |
| 1714 | 1720 | } |
| 1715 | 1721 | |
| 1722 | + err = ubifs_node_check_hash(c, buf, zbr->hash); | |
| 1723 | + if (err) { | |
| 1724 | + ubifs_bad_hash(c, buf, zbr->hash, zbr->lnum, zbr->offs); | |
| 1725 | + return err; | |
| 1726 | + } | |
| 1727 | + | |
| 1716 | 1728 | len = le32_to_cpu(ch->len); |
| 1717 | 1729 | if (len != zbr->len) { |
| 1718 | 1730 | ubifs_err(c, "bad node length %d, expected %d", len, zbr->len); |
| @@ -2260,13 +2272,14 @@ do_split: · 541 unmodified lines | ||
| 2260 | 2272 | * @lnum: LEB number of node |
| 2261 | 2273 | * @offs: node offset |
| 2262 | 2274 | * @len: node length |
| 2275 | + * @hash: The hash over the node | |
| 2263 | 2276 | * |
| 2264 | 2277 | * This function adds a node with key @key to TNC. The node may be new or it may |
| 2265 | 2278 | * obsolete some existing one. Returns %0 on success or negative error code on |
| 2266 | 2279 | * failure. |
| 2267 | 2280 | */ |
| 2268 | 2281 | int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, |
| 2269 | − int offs, int len) | |
| 2282 | + int offs, int len, const u8 *hash) | |
| 2270 | 2283 | { |
| 2271 | 2284 | int found, n, err = 0; |
| 2272 | 2285 | struct ubifs_znode *znode; |
| @@ -2281,6 +2294,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, · 8 unmodified lines | ||
| 2281 | 2294 | zbr.lnum = lnum; |
| 2282 | 2295 | zbr.offs = offs; |
| 2283 | 2296 | zbr.len = len; |
| 2297 | + ubifs_copy_hash(c, hash, zbr.hash); | |
| 2284 | 2298 | key_copy(c, key, &zbr.key); |
| 2285 | 2299 | err = tnc_insert(c, znode, &zbr, n + 1); |
| 2286 | 2300 | } else if (found == 1) { |
| @@ -2291,6 +2305,7 @@ int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, · 4 unmodified lines | ||
| 2291 | 2305 | zbr->lnum = lnum; |
| 2292 | 2306 | zbr->offs = offs; |
| 2293 | 2307 | zbr->len = len; |
| 2308 | + ubifs_copy_hash(c, hash, zbr->hash); | |
| 2294 | 2309 | } else |
| 2295 | 2310 | err = found; |
| 2296 | 2311 | if (!err) |
| @@ -2392,13 +2407,14 @@ out_unlock: · 95 unmodified lines | ||
| 2392 | 2407 | * @lnum: LEB number of node |
| 2393 | 2408 | * @offs: node offset |
| 2394 | 2409 | * @len: node length |
| 2410 | + * @hash: The hash over the node | |
| 2395 | 2411 | * @nm: node name |
| 2396 | 2412 | * |
| 2397 | 2413 | * This is the same as 'ubifs_tnc_add()' but it should be used with keys which |
| 2398 | 2414 | * may have collisions, like directory entry keys. |
| 2399 | 2415 | */ |
| 2400 | 2416 | int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, |
| 2401 | − int lnum, int offs, int len, | |
| 2417 | + int lnum, int offs, int len, const u8 *hash, | |
| 2402 | 2418 | const struct fscrypt_name *nm) |
| 2403 | 2419 | { |
| 2404 | 2420 | int found, n, err = 0; |
| @@ -2441,6 +2457,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, · 36 unmodified lines | ||
| 2441 | 2457 | zbr->lnum = lnum; |
| 2442 | 2458 | zbr->offs = offs; |
| 2443 | 2459 | zbr->len = len; |
| 2460 | + ubifs_copy_hash(c, hash, zbr->hash); | |
| 2444 | 2461 | goto out_unlock; |
| 2445 | 2462 | } |
| 2446 | 2463 | } |
| @@ -2452,6 +2469,7 @@ int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, · 5 unmodified lines | ||
| 2452 | 2469 | zbr.lnum = lnum; |
| 2453 | 2470 | zbr.offs = offs; |
| 2454 | 2471 | zbr.len = len; |
| 2472 | + ubifs_copy_hash(c, hash, zbr.hash); | |
| 2455 | 2473 | key_copy(c, key, &zbr.key); |
| 2456 | 2474 | err = tnc_insert(c, znode, &zbr, n + 1); |
| 2457 | 2475 | if (err) |
| @@ -38,6 +38,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, · 37 unmodified lines | ||
| 38 | 38 | struct ubifs_znode *znode, int lnum, int offs, int len) |
| 39 | 39 | { |
| 40 | 40 | struct ubifs_znode *zp; |
| 41 | + u8 hash[UBIFS_HASH_ARR_SZ]; | |
| 41 | 42 | int i, err; |
| 42 | 43 | |
| 43 | 44 | /* Make index node */ |
| @@ -52,6 +53,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, · 8 unmodified lines | ||
| 52 | 53 | br->lnum = cpu_to_le32(zbr->lnum); |
| 53 | 54 | br->offs = cpu_to_le32(zbr->offs); |
| 54 | 55 | br->len = cpu_to_le32(zbr->len); |
| 56 | + ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br)); | |
| 55 | 57 | if (!zbr->lnum || !zbr->len) { |
| 56 | 58 | ubifs_err(c, "bad ref in znode"); |
| 57 | 59 | ubifs_dump_znode(c, znode); |
| @@ -62,6 +64,7 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, · 4 unmodified lines | ||
| 62 | 64 | } |
| 63 | 65 | } |
| 64 | 66 | ubifs_prepare_node(c, idx, len, 0); |
| 67 | + ubifs_node_calc_hash(c, idx, hash); | |
| 65 | 68 | |
| 66 | 69 | znode->lnum = lnum; |
| 67 | 70 | znode->offs = offs; |
| @@ -78,10 +81,12 @@ static int make_idx_node(struct ubifs_info *c, struct ubifs_idx_node *idx, · 10 unmodified lines | ||
| 78 | 81 | zbr->lnum = lnum; |
| 79 | 82 | zbr->offs = offs; |
| 80 | 83 | zbr->len = len; |
| 84 | + ubifs_copy_hash(c, hash, zbr->hash); | |
| 81 | 85 | } else { |
| 82 | 86 | c->zroot.lnum = lnum; |
| 83 | 87 | c->zroot.offs = offs; |
| 84 | 88 | c->zroot.len = len; |
| 89 | + ubifs_copy_hash(c, hash, c->zroot.hash); | |
| 85 | 90 | } |
| 86 | 91 | c->calc_idx_sz += ALIGN(len, 8); |
| 87 | 92 | |
| @@ -647,6 +652,8 @@ static int get_znodes_to_commit(struct ubifs_info *c) · 559 unmodified lines | ||
| 647 | 652 | znode->cnext = c->cnext; |
| 648 | 653 | break; |
| 649 | 654 | } |
| 655 | + znode->cparent = znode->parent; | |
| 656 | + znode->ciip = znode->iip; | |
| 650 | 657 | znode->cnext = cnext; |
| 651 | 658 | znode = cnext; |
| 652 | 659 | cnt += 1; |
| @@ -840,6 +847,8 @@ static int write_index(struct ubifs_info *c) · 187 unmodified lines | ||
| 840 | 847 | } |
| 841 | 848 | |
| 842 | 849 | while (1) { |
| 850 | + u8 hash[UBIFS_HASH_ARR_SZ]; | |
| 851 | + | |
| 843 | 852 | cond_resched(); |
| 844 | 853 | |
| 845 | 854 | znode = cnext; |
| @@ -857,6 +866,7 @@ static int write_index(struct ubifs_info *c) · 11 unmodified lines | ||
| 857 | 866 | br->lnum = cpu_to_le32(zbr->lnum); |
| 858 | 867 | br->offs = cpu_to_le32(zbr->offs); |
| 859 | 868 | br->len = cpu_to_le32(zbr->len); |
| 869 | + ubifs_copy_hash(c, zbr->hash, ubifs_branch_hash(c, br)); | |
| 860 | 870 | if (!zbr->lnum || !zbr->len) { |
| 861 | 871 | ubifs_err(c, "bad ref in znode"); |
| 862 | 872 | ubifs_dump_znode(c, znode); |
| @@ -868,6 +878,23 @@ static int write_index(struct ubifs_info *c) · 5 unmodified lines | ||
| 868 | 878 | } |
| 869 | 879 | len = ubifs_idx_node_sz(c, znode->child_cnt); |
| 870 | 880 | ubifs_prepare_node(c, idx, len, 0); |
| 881 | + ubifs_node_calc_hash(c, idx, hash); | |
| 882 | + | |
| 883 | + mutex_lock(&c->tnc_mutex); | |
| 884 | + | |
| 885 | + if (znode->cparent) | |
| 886 | + ubifs_copy_hash(c, hash, | |
| 887 | + znode->cparent->zbranch[znode->ciip].hash); | |
| 888 | + | |
| 889 | + if (znode->parent) { | |
| 890 | + if (!ubifs_zn_obsolete(znode)) | |
| 891 | + ubifs_copy_hash(c, hash, | |
| 892 | + znode->parent->zbranch[znode->iip].hash); | |
| 893 | + } else { | |
| 894 | + ubifs_copy_hash(c, hash, c->zroot.hash); | |
| 895 | + } | |
| 896 | + | |
| 897 | + mutex_unlock(&c->tnc_mutex); | |
| 871 | 898 | |
| 872 | 899 | /* Determine the index node position */ |
| 873 | 900 | if (lnum == -1) { |
| @@ -265,9 +265,7 @@ long ubifs_destroy_tnc_subtree(const struct ubifs_info *c, · 264 unmodified lines | ||
| 265 | 265 | /** |
| 266 | 266 | * read_znode - read an indexing node from flash and fill znode. |
| 267 | 267 | * @c: UBIFS file-system description object |
| 268 | − * @lnum: LEB of the indexing node to read | |
| 269 | − * @offs: node offset | |
| 270 | − * @len: node length | |
| 268 | + * @zzbr: the zbranch describing the node to read | |
| 271 | 269 | * @znode: znode to read to |
| 272 | 270 | * |
| 273 | 271 | * This function reads an indexing node from the flash media and fills znode |
| @@ -276,9 +274,12 @@ long ubifs_destroy_tnc_subtree(const struct ubifs_info *c, · 2 unmodified lines | ||
| 276 | 274 | * is wrong with it, this function prints complaint messages and returns |
| 277 | 275 | * %-EINVAL. |
| 278 | 276 | */ |
| 279 | −static int read_znode(struct ubifs_info *c, int lnum, int offs, int len, | |
| 277 | +static int read_znode(struct ubifs_info *c, struct ubifs_zbranch *zzbr, | |
| 280 | 278 | struct ubifs_znode *znode) |
| 281 | 279 | { |
| 280 | + int lnum = zzbr->lnum; | |
| 281 | + int offs = zzbr->offs; | |
| 282 | + int len = zzbr->len; | |
| 282 | 283 | int i, err, type, cmp; |
| 283 | 284 | struct ubifs_idx_node *idx; |
| 284 | 285 | |
| @@ -292,6 +293,12 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len, · 7 unmodified lines | ||
| 292 | 293 | return err; |
| 293 | 294 | } |
| 294 | 295 | |
| 296 | + err = ubifs_node_check_hash(c, idx, zzbr->hash); | |
| 297 | + if (err) { | |
| 298 | + ubifs_bad_hash(c, idx, zzbr->hash, lnum, offs); | |
| 299 | + return err; | |
| 300 | + } | |
| 301 | + | |
| 295 | 302 | znode->child_cnt = le16_to_cpu(idx->child_cnt); |
| 296 | 303 | znode->level = le16_to_cpu(idx->level); |
| 297 | 304 | |
| @@ -308,13 +315,14 @@ static int read_znode(struct ubifs_info *c, int lnum, int offs, int len, · 10 unmodified lines | ||
| 308 | 315 | } |
| 309 | 316 | |
| 310 | 317 | for (i = 0; i < znode->child_cnt; i++) { |
| 311 | − const struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); | |
| 318 | + struct ubifs_branch *br = ubifs_idx_branch(c, idx, i); | |
| 312 | 319 | struct ubifs_zbranch *zbr = &znode->zbranch[i]; |
| 313 | 320 | |
| 314 | 321 | key_read(c, &br->key, &zbr->key); |
| 315 | 322 | zbr->lnum = le32_to_cpu(br->lnum); |
| 316 | 323 | zbr->offs = le32_to_cpu(br->offs); |
| 317 | 324 | zbr->len = le32_to_cpu(br->len); |
| 325 | + ubifs_copy_hash(c, ubifs_branch_hash(c, br), zbr->hash); | |
| 318 | 326 | zbr->znode = NULL; |
| 319 | 327 | |
| 320 | 328 | /* Validate branch */ |
| @@ -425,7 +433,7 @@ struct ubifs_znode *ubifs_load_znode(struct ubifs_info *c, · 104 unmodified lines | ||
| 425 | 433 | if (!znode) |
| 426 | 434 | return ERR_PTR(-ENOMEM); |
| 427 | 435 | |
| 428 | − err = read_znode(c, zbr->lnum, zbr->offs, zbr->len, znode); | |
| 436 | + err = read_znode(c, zbr, znode); | |
| 429 | 437 | if (err) |
| 430 | 438 | goto out; |
| 431 | 439 | |
| @@ -496,5 +504,11 @@ int ubifs_tnc_read_node(struct ubifs_info *c, struct ubifs_zbranch *zbr, · 64 unmodified lines | ||
| 496 | 504 | return -EINVAL; |
| 497 | 505 | } |
| 498 | 506 | |
| 507 | + err = ubifs_node_check_hash(c, node, zbr->hash); | |
| 508 | + if (err) { | |
| 509 | + ubifs_bad_hash(c, node, zbr->hash, zbr->lnum, zbr->offs); | |
| 510 | + return err; | |
| 511 | + } | |
| 512 | + | |
| 499 | 513 | return 0; |
| 500 | 514 | } |
| @@ -286,6 +286,7 @@ enum { · 285 unmodified lines | ||
| 286 | 286 | #define UBIFS_IDX_NODE_SZ sizeof(struct ubifs_idx_node) |
| 287 | 287 | #define UBIFS_CS_NODE_SZ sizeof(struct ubifs_cs_node) |
| 288 | 288 | #define UBIFS_ORPH_NODE_SZ sizeof(struct ubifs_orph_node) |
| 289 | +#define UBIFS_AUTH_NODE_SZ sizeof(struct ubifs_auth_node) | |
| 289 | 290 | /* Extended attribute entry nodes are identical to directory entry nodes */ |
| 290 | 291 | #define UBIFS_XENT_NODE_SZ UBIFS_DENT_NODE_SZ |
| 291 | 292 | /* Only this does not have to be multiple of 8 bytes */ |
| @@ -300,6 +301,12 @@ enum { · 8 unmodified lines | ||
| 300 | 301 | /* The largest UBIFS node */ |
| 301 | 302 | #define UBIFS_MAX_NODE_SZ UBIFS_MAX_INO_NODE_SZ |
| 302 | 303 | |
| 304 | +/* The maxmimum size of a hash, enough for sha512 */ | |
| 305 | +#define UBIFS_MAX_HASH_LEN 64 | |
| 306 | + | |
| 307 | +/* The maxmimum size of a hmac, enough for hmac(sha512) */ | |
| 308 | +#define UBIFS_MAX_HMAC_LEN 64 | |
| 309 | + | |
| 303 | 310 | /* |
| 304 | 311 | * xattr name of UBIFS encryption context, we don't use a prefix |
| 305 | 312 | * nor a long name to not waste space on the flash. |
| @@ -365,6 +372,7 @@ enum { · 59 unmodified lines | ||
| 365 | 372 | * UBIFS_IDX_NODE: index node |
| 366 | 373 | * UBIFS_CS_NODE: commit start node |
| 367 | 374 | * UBIFS_ORPH_NODE: orphan node |
| 375 | + * UBIFS_AUTH_NODE: authentication node | |
| 368 | 376 | * UBIFS_NODE_TYPES_CNT: count of supported node types |
| 369 | 377 | * |
| 370 | 378 | * Note, we index arrays by these numbers, so keep them low and contiguous. |
| @@ -384,6 +392,7 @@ enum { · 13 unmodified lines | ||
| 384 | 392 | UBIFS_IDX_NODE, |
| 385 | 393 | UBIFS_CS_NODE, |
| 386 | 394 | UBIFS_ORPH_NODE, |
| 395 | + UBIFS_AUTH_NODE, | |
| 387 | 396 | UBIFS_NODE_TYPES_CNT, |
| 388 | 397 | }; |
| 389 | 398 | |
| @@ -421,15 +430,19 @@ enum { · 31 unmodified lines | ||
| 421 | 430 | * UBIFS_FLG_DOUBLE_HASH: store a 32bit cookie in directory entry nodes to |
| 422 | 431 | * support 64bit cookies for lookups by hash |
| 423 | 432 | * UBIFS_FLG_ENCRYPTION: this filesystem contains encrypted files |
| 433 | + * UBIFS_FLG_AUTHENTICATION: this filesystem contains hashes for authentication | |
| 424 | 434 | */ |
| 425 | 435 | enum { |
| 426 | 436 | UBIFS_FLG_BIGLPT = 0x02, |
| 427 | 437 | UBIFS_FLG_SPACE_FIXUP = 0x04, |
| 428 | 438 | UBIFS_FLG_DOUBLE_HASH = 0x08, |
| 429 | 439 | UBIFS_FLG_ENCRYPTION = 0x10, |
| 440 | + UBIFS_FLG_AUTHENTICATION = 0x20, | |
| 430 | 441 | }; |
| 431 | 442 | |
| 432 | −#define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT|UBIFS_FLG_SPACE_FIXUP|UBIFS_FLG_DOUBLE_HASH|UBIFS_FLG_ENCRYPTION) | |
| 443 | +#define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT | UBIFS_FLG_SPACE_FIXUP | \ | |
| 444 | + UBIFS_FLG_DOUBLE_HASH | UBIFS_FLG_ENCRYPTION | \ | |
| 445 | + UBIFS_FLG_AUTHENTICATION) | |
| 433 | 446 | |
| 434 | 447 | /** |
| 435 | 448 | * struct ubifs_ch - common header node. |
| @@ -633,6 +646,10 @@ struct ubifs_pad_node { · 197 unmodified lines | ||
| 633 | 646 | * @time_gran: time granularity in nanoseconds |
| 634 | 647 | * @uuid: UUID generated when the file system image was created |
| 635 | 648 | * @ro_compat_version: UBIFS R/O compatibility version |
| 649 | + * @hmac: HMAC to authenticate the superblock node | |
| 650 | + * @hmac_wkm: HMAC of a well known message (the string "UBIFS") as a convenience | |
| 651 | + * to the user to check if the correct key is passed. | |
| 652 | + * @hash_algo: The hash algo used for this filesystem (one of enum hash_algo) | |
| 636 | 653 | */ |
| 637 | 654 | struct ubifs_sb_node { |
| 638 | 655 | struct ubifs_ch ch; |
| @@ -660,7 +677,10 @@ struct ubifs_sb_node { · 21 unmodified lines | ||
| 660 | 677 | __le32 time_gran; |
| 661 | 678 | __u8 uuid[16]; |
| 662 | 679 | __le32 ro_compat_version; |
| 663 | − __u8 padding2[3968]; | |
| 680 | + __u8 hmac[UBIFS_MAX_HMAC_LEN]; | |
| 681 | + __u8 hmac_wkm[UBIFS_MAX_HMAC_LEN]; | |
| 682 | + __le16 hash_algo; | |
| 683 | + __u8 padding2[3838]; | |
| 664 | 684 | } __packed; |
| 665 | 685 | |
| 666 | 686 | /** |
| @@ -695,6 +715,9 @@ struct ubifs_sb_node { · 28 unmodified lines | ||
| 695 | 715 | * @empty_lebs: number of empty logical eraseblocks |
| 696 | 716 | * @idx_lebs: number of indexing logical eraseblocks |
| 697 | 717 | * @leb_cnt: count of LEBs used by file-system |
| 718 | + * @hash_root_idx: the hash of the root index node | |
| 719 | + * @hash_lpt: the hash of the LPT | |
| 720 | + * @hmac: HMAC to authenticate the master node | |
| 698 | 721 | * @padding: reserved for future, zeroes |
| 699 | 722 | */ |
| 700 | 723 | struct ubifs_mst_node { |
| @@ -727,7 +750,10 @@ struct ubifs_mst_node { · 26 unmodified lines | ||
| 727 | 750 | __le32 empty_lebs; |
| 728 | 751 | __le32 idx_lebs; |
| 729 | 752 | __le32 leb_cnt; |
| 730 | − __u8 padding[344]; | |
| 753 | + __u8 hash_root_idx[UBIFS_MAX_HASH_LEN]; | |
| 754 | + __u8 hash_lpt[UBIFS_MAX_HASH_LEN]; | |
| 755 | + __u8 hmac[UBIFS_MAX_HMAC_LEN]; | |
| 756 | + __u8 padding[152]; | |
| 731 | 757 | } __packed; |
| 732 | 758 | |
| 733 | 759 | /** |
| @@ -746,12 +772,26 @@ struct ubifs_ref_node { · 12 unmodified lines | ||
| 746 | 772 | __u8 padding[28]; |
| 747 | 773 | } __packed; |
| 748 | 774 | |
| 775 | +/** | |
| 776 | + * struct ubifs_auth_node - node for authenticating other nodes | |
| 777 | + * @ch: common header | |
| 778 | + * @hmac: The HMAC | |
| 779 | + */ | |
| 780 | +struct ubifs_auth_node { | |
| 781 | + struct ubifs_ch ch; | |
| 782 | + __u8 hmac[]; | |
| 783 | +} __packed; | |
| 784 | + | |
| 749 | 785 | /** |
| 750 | 786 | * struct ubifs_branch - key/reference/length branch |
| 751 | 787 | * @lnum: LEB number of the target node |
| 752 | 788 | * @offs: offset within @lnum |
| 753 | 789 | * @len: target node length |
| 754 | 790 | * @key: key |
| 791 | + * | |
| 792 | + * In an authenticated UBIFS we have the hash of the referenced node after @key. | |
| 793 | + * This can't be added to the struct type definition because @key is a | |
| 794 | + * dynamically sized element already. | |
| 755 | 795 | */ |
| 756 | 796 | struct ubifs_branch { |
| 757 | 797 | __le32 lnum; |
| @@ -39,6 +39,9 @@ · 38 unmodified lines | ||
| 39 | 39 | #include <linux/security.h> |
| 40 | 40 | #include <linux/xattr.h> |
| 41 | 41 | #include <linux/random.h> |
| 42 | +#include <crypto/hash_info.h> | |
| 43 | +#include <crypto/hash.h> | |
| 44 | +#include <crypto/algapi.h> | |
| 42 | 45 | |
| 43 | 46 | #define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_UBIFS_FS_ENCRYPTION) |
| 44 | 47 | #include <linux/fscrypt.h> |
| @@ -157,6 +160,14 @@ · 112 unmodified lines | ||
| 157 | 160 | /* Maximum number of data nodes to bulk-read */ |
| 158 | 161 | #define UBIFS_MAX_BULK_READ 32 |
| 159 | 162 | |
| 163 | +#ifdef CONFIG_UBIFS_FS_AUTHENTICATION | |
| 164 | +#define UBIFS_HASH_ARR_SZ UBIFS_MAX_HASH_LEN | |
| 165 | +#define UBIFS_HMAC_ARR_SZ UBIFS_MAX_HMAC_LEN | |
| 166 | +#else | |
| 167 | +#define UBIFS_HASH_ARR_SZ 0 | |
| 168 | +#define UBIFS_HMAC_ARR_SZ 0 | |
| 169 | +#endif | |
| 170 | + | |
| 160 | 171 | /* |
| 161 | 172 | * Lockdep classes for UBIFS inode @ui_mutex. |
| 162 | 173 | */ |
| @@ -706,6 +717,7 @@ struct ubifs_wbuf { · 543 unmodified lines | ||
| 706 | 717 | * @jhead: journal head number this bud belongs to |
| 707 | 718 | * @list: link in the list buds belonging to the same journal head |
| 708 | 719 | * @rb: link in the tree of all buds |
| 720 | + * @log_hash: the log hash from the commit start node up to this bud | |
| 709 | 721 | */ |
| 710 | 722 | struct ubifs_bud { |
| 711 | 723 | int lnum; |
| @@ -713,6 +725,7 @@ struct ubifs_bud { · 1 unmodified line | ||
| 713 | 725 | int jhead; |
| 714 | 726 | struct list_head list; |
| 715 | 727 | struct rb_node rb; |
| 728 | + struct shash_desc *log_hash; | |
| 716 | 729 | }; |
| 717 | 730 | |
| 718 | 731 | /** |
| @@ -720,6 +733,7 @@ struct ubifs_bud { · 1 unmodified line | ||
| 720 | 733 | * @wbuf: head's write-buffer |
| 721 | 734 | * @buds_list: list of bud LEBs belonging to this journal head |
| 722 | 735 | * @grouped: non-zero if UBIFS groups nodes when writing to this journal head |
| 736 | + * @log_hash: the log hash from the commit start node up to this journal head | |
| 723 | 737 | * |
| 724 | 738 | * Note, the @buds list is protected by the @c->buds_lock. |
| 725 | 739 | */ |
| @@ -727,6 +741,7 @@ struct ubifs_jhead { · 1 unmodified line | ||
| 727 | 741 | struct ubifs_wbuf wbuf; |
| 728 | 742 | struct list_head buds_list; |
| 729 | 743 | unsigned int grouped:1; |
| 744 | + struct shash_desc *log_hash; | |
| 730 | 745 | }; |
| 731 | 746 | |
| 732 | 747 | /** |
| @@ -736,6 +751,7 @@ struct ubifs_jhead { · 3 unmodified lines | ||
| 736 | 751 | * @lnum: LEB number of the target node (indexing node or data node) |
| 737 | 752 | * @offs: target node offset within @lnum |
| 738 | 753 | * @len: target node length |
| 754 | + * @hash: the hash of the target node | |
| 739 | 755 | */ |
| 740 | 756 | struct ubifs_zbranch { |
| 741 | 757 | union ubifs_key key; |
| @@ -746,12 +762,15 @@ struct ubifs_zbranch { · 4 unmodified lines | ||
| 746 | 762 | int lnum; |
| 747 | 763 | int offs; |
| 748 | 764 | int len; |
| 765 | + u8 hash[UBIFS_HASH_ARR_SZ]; | |
| 749 | 766 | }; |
| 750 | 767 | |
| 751 | 768 | /** |
| 752 | 769 | * struct ubifs_znode - in-memory representation of an indexing node. |
| 753 | 770 | * @parent: parent znode or NULL if it is the root |
| 754 | 771 | * @cnext: next znode to commit |
| 772 | + * @cparent: parent node for this commit | |
| 773 | + * @ciip: index in cparent's zbranch array | |
| 755 | 774 | * @flags: znode flags (%DIRTY_ZNODE, %COW_ZNODE or %OBSOLETE_ZNODE) |
| 756 | 775 | * @time: last access time (seconds) |
| 757 | 776 | * @level: level of the entry in the TNC tree |
| @@ -769,6 +788,8 @@ struct ubifs_zbranch { · 11 unmodified lines | ||
| 769 | 788 | struct ubifs_znode { |
| 770 | 789 | struct ubifs_znode *parent; |
| 771 | 790 | struct ubifs_znode *cnext; |
| 791 | + struct ubifs_znode *cparent; | |
| 792 | + int ciip; | |
| 772 | 793 | unsigned long flags; |
| 773 | 794 | time64_t time; |
| 774 | 795 | int level; |
| @@ -983,6 +1004,7 @@ struct ubifs_debug_info; · 208 unmodified lines | ||
| 983 | 1004 | * struct ubifs_info - UBIFS file-system description data structure |
| 984 | 1005 | * (per-superblock). |
| 985 | 1006 | * @vfs_sb: VFS @struct super_block object |
| 1007 | + * @sup_node: The super block node as read from the device | |
| 986 | 1008 | * |
| 987 | 1009 | * @highest_inum: highest used inode number |
| 988 | 1010 | * @max_sqnum: current global sequence number |
| @@ -1028,6 +1050,7 @@ struct ubifs_debug_info; · 39 unmodified lines | ||
| 1028 | 1050 | * @default_compr: default compression algorithm (%UBIFS_COMPR_LZO, etc) |
| 1029 | 1051 | * @rw_incompat: the media is not R/W compatible |
| 1030 | 1052 | * @assert_action: action to take when a ubifs_assert() fails |
| 1053 | + * @authenticated: flag indigating the FS is mounted in authenticated mode | |
| 1031 | 1054 | * |
| 1032 | 1055 | * @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and |
| 1033 | 1056 | * @calc_idx_sz |
| @@ -1075,6 +1098,7 @@ struct ubifs_debug_info; · 41 unmodified lines | ||
| 1075 | 1098 | * @key_hash: direntry key hash function |
| 1076 | 1099 | * @key_fmt: key format |
| 1077 | 1100 | * @key_len: key length |
| 1101 | + * @hash_len: The length of the index node hashes | |
| 1078 | 1102 | * @fanout: fanout of the index tree (number of links per indexing node) |
| 1079 | 1103 | * |
| 1080 | 1104 | * @min_io_size: minimal input/output unit size |
| @@ -1210,6 +1234,15 @@ struct ubifs_debug_info; · 129 unmodified lines | ||
| 1210 | 1234 | * @rp_uid: reserved pool user ID |
| 1211 | 1235 | * @rp_gid: reserved pool group ID |
| 1212 | 1236 | * |
| 1237 | + * @hash_tfm: the hash transformation used for hashing nodes | |
| 1238 | + * @hmac_tfm: the HMAC transformation for this filesystem | |
| 1239 | + * @hmac_desc_len: length of the HMAC used for authentication | |
| 1240 | + * @auth_key_name: the authentication key name | |
| 1241 | + * @auth_hash_name: the name of the hash algorithm used for authentication | |
| 1242 | + * @auth_hash_algo: the authentication hash used for this fs | |
| 1243 | + * @log_hash: the log hash from the commit start node up to the latest reference | |
| 1244 | + * node. | |
| 1245 | + * | |
| 1213 | 1246 | * @empty: %1 if the UBI device is empty |
| 1214 | 1247 | * @need_recovery: %1 if the file-system needs recovery |
| 1215 | 1248 | * @replaying: %1 during journal replay |
| @@ -1230,6 +1263,7 @@ struct ubifs_debug_info; · 14 unmodified lines | ||
| 1230 | 1263 | */ |
| 1231 | 1264 | struct ubifs_info { |
| 1232 | 1265 | struct super_block *vfs_sb; |
| 1266 | + struct ubifs_sb_node *sup_node; | |
| 1233 | 1267 | |
| 1234 | 1268 | ino_t highest_inum; |
| 1235 | 1269 | unsigned long long max_sqnum; |
| @@ -1270,6 +1304,7 @@ struct ubifs_info { · 34 unmodified lines | ||
| 1270 | 1304 | unsigned int default_compr:2; |
| 1271 | 1305 | unsigned int rw_incompat:1; |
| 1272 | 1306 | unsigned int assert_action:2; |
| 1307 | + unsigned int authenticated:1; | |
| 1273 | 1308 | |
| 1274 | 1309 | struct mutex tnc_mutex; |
| 1275 | 1310 | struct ubifs_zbranch zroot; |
| @@ -1314,6 +1349,7 @@ struct ubifs_info { · 38 unmodified lines | ||
| 1314 | 1349 | uint32_t (*key_hash)(const char *str, int len); |
| 1315 | 1350 | int key_fmt; |
| 1316 | 1351 | int key_len; |
| 1352 | + int hash_len; | |
| 1317 | 1353 | int fanout; |
| 1318 | 1354 | |
| 1319 | 1355 | int min_io_size; |
| @@ -1441,6 +1477,15 @@ struct ubifs_info { · 121 unmodified lines | ||
| 1441 | 1477 | kuid_t rp_uid; |
| 1442 | 1478 | kgid_t rp_gid; |
| 1443 | 1479 | |
| 1480 | + struct crypto_shash *hash_tfm; | |
| 1481 | + struct crypto_shash *hmac_tfm; | |
| 1482 | + int hmac_desc_len; | |
| 1483 | + char *auth_key_name; | |
| 1484 | + char *auth_hash_name; | |
| 1485 | + enum hash_algo auth_hash_algo; | |
| 1486 | + | |
| 1487 | + struct shash_desc *log_hash; | |
| 1488 | + | |
| 1444 | 1489 | /* The below fields are used only during mounting and re-mounting */ |
| 1445 | 1490 | unsigned int empty:1; |
| 1446 | 1491 | unsigned int need_recovery:1; |
| @@ -1471,6 +1516,195 @@ extern const struct inode_operations ubifs_dir_inode_operations; · 24 unmodified lines | ||
| 1471 | 1516 | extern const struct inode_operations ubifs_symlink_inode_operations; |
| 1472 | 1517 | extern struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT]; |
| 1473 | 1518 | |
| 1519 | +/* auth.c */ | |
| 1520 | +static inline int ubifs_authenticated(const struct ubifs_info *c) | |
| 1521 | +{ | |
| 1522 | + return (IS_ENABLED(CONFIG_UBIFS_FS_AUTHENTICATION)) && c->authenticated; | |
| 1523 | +} | |
| 1524 | + | |
| 1525 | +struct shash_desc *__ubifs_hash_get_desc(const struct ubifs_info *c); | |
| 1526 | +static inline struct shash_desc *ubifs_hash_get_desc(const struct ubifs_info *c) | |
| 1527 | +{ | |
| 1528 | + return ubifs_authenticated(c) ? __ubifs_hash_get_desc(c) : NULL; | |
| 1529 | +} | |
| 1530 | + | |
| 1531 | +static inline int ubifs_shash_init(const struct ubifs_info *c, | |
| 1532 | + struct shash_desc *desc) | |
| 1533 | +{ | |
| 1534 | + if (ubifs_authenticated(c)) | |
| 1535 | + return crypto_shash_init(desc); | |
| 1536 | + else | |
| 1537 | + return 0; | |
| 1538 | +} | |
| 1539 | + | |
| 1540 | +static inline int ubifs_shash_update(const struct ubifs_info *c, | |
| 1541 | + struct shash_desc *desc, const void *buf, | |
| 1542 | + unsigned int len) | |
| 1543 | +{ | |
| 1544 | + int err = 0; | |
| 1545 | + | |
| 1546 | + if (ubifs_authenticated(c)) { | |
| 1547 | + err = crypto_shash_update(desc, buf, len); | |
| 1548 | + if (err < 0) | |
| 1549 | + return err; | |
| 1550 | + } | |
| 1551 | + | |
| 1552 | + return 0; | |
| 1553 | +} | |
| 1554 | + | |
| 1555 | +static inline int ubifs_shash_final(const struct ubifs_info *c, | |
| 1556 | + struct shash_desc *desc, u8 *out) | |
| 1557 | +{ | |
| 1558 | + return ubifs_authenticated(c) ? crypto_shash_final(desc, out) : 0; | |
| 1559 | +} | |
| 1560 | + | |
| 1561 | +int __ubifs_node_calc_hash(const struct ubifs_info *c, const void *buf, | |
| 1562 | + u8 *hash); | |
| 1563 | +static inline int ubifs_node_calc_hash(const struct ubifs_info *c, | |
| 1564 | + const void *buf, u8 *hash) | |
| 1565 | +{ | |
| 1566 | + if (ubifs_authenticated(c)) | |
| 1567 | + return __ubifs_node_calc_hash(c, buf, hash); | |
| 1568 | + else | |
| 1569 | + return 0; | |
| 1570 | +} | |
| 1571 | + | |
| 1572 | +int ubifs_prepare_auth_node(struct ubifs_info *c, void *node, | |
| 1573 | + struct shash_desc *inhash); | |
| 1574 | + | |
| 1575 | +/** | |
| 1576 | + * ubifs_check_hash - compare two hashes | |
| 1577 | + * @c: UBIFS file-system description object | |
| 1578 | + * @expected: first hash | |
| 1579 | + * @got: second hash | |
| 1580 | + * | |
| 1581 | + * Compare two hashes @expected and @got. Returns 0 when they are equal, a | |
| 1582 | + * negative error code otherwise. | |
| 1583 | + */ | |
| 1584 | +static inline int ubifs_check_hash(const struct ubifs_info *c, | |
| 1585 | + const u8 *expected, const u8 *got) | |
| 1586 | +{ | |
| 1587 | + return crypto_memneq(expected, got, c->hash_len); | |
| 1588 | +} | |
| 1589 | + | |
| 1590 | +/** | |
| 1591 | + * ubifs_check_hmac - compare two HMACs | |
| 1592 | + * @c: UBIFS file-system description object | |
| 1593 | + * @expected: first HMAC | |
| 1594 | + * @got: second HMAC | |
| 1595 | + * | |
| 1596 | + * Compare two hashes @expected and @got. Returns 0 when they are equal, a | |
| 1597 | + * negative error code otherwise. | |
| 1598 | + */ | |
| 1599 | +static inline int ubifs_check_hmac(const struct ubifs_info *c, | |
| 1600 | + const u8 *expected, const u8 *got) | |
| 1601 | +{ | |
| 1602 | + return crypto_memneq(expected, got, c->hmac_desc_len); | |
| 1603 | +} | |
| 1604 | + | |
| 1605 | +void ubifs_bad_hash(const struct ubifs_info *c, const void *node, | |
| 1606 | + const u8 *hash, int lnum, int offs); | |
| 1607 | + | |
| 1608 | +int __ubifs_node_check_hash(const struct ubifs_info *c, const void *buf, | |
| 1609 | + const u8 *expected); | |
| 1610 | +static inline int ubifs_node_check_hash(const struct ubifs_info *c, | |
| 1611 | + const void *buf, const u8 *expected) | |
| 1612 | +{ | |
| 1613 | + if (ubifs_authenticated(c)) | |
| 1614 | + return __ubifs_node_check_hash(c, buf, expected); | |
| 1615 | + else | |
| 1616 | + return 0; | |
| 1617 | +} | |
| 1618 | + | |
| 1619 | +int ubifs_init_authentication(struct ubifs_info *c); | |
| 1620 | +void __ubifs_exit_authentication(struct ubifs_info *c); | |
| 1621 | +static inline void ubifs_exit_authentication(struct ubifs_info *c) | |
| 1622 | +{ | |
| 1623 | + if (ubifs_authenticated(c)) | |
| 1624 | + __ubifs_exit_authentication(c); | |
| 1625 | +} | |
| 1626 | + | |
| 1627 | +/** | |
| 1628 | + * ubifs_branch_hash - returns a pointer to the hash of a branch | |
| 1629 | + * @c: UBIFS file-system description object | |
| 1630 | + * @br: branch to get the hash from | |
| 1631 | + * | |
| 1632 | + * This returns a pointer to the hash of a branch. Since the key already is a | |
| 1633 | + * dynamically sized object we cannot use a struct member here. | |
| 1634 | + */ | |
| 1635 | +static inline u8 *ubifs_branch_hash(struct ubifs_info *c, | |
| 1636 | + struct ubifs_branch *br) | |
| 1637 | +{ | |
| 1638 | + return (void *)br + sizeof(*br) + c->key_len; | |
| 1639 | +} | |
| 1640 | + | |
| 1641 | +/** | |
| 1642 | + * ubifs_copy_hash - copy a hash | |
| 1643 | + * @c: UBIFS file-system description object | |
| 1644 | + * @from: source hash | |
| 1645 | + * @to: destination hash | |
| 1646 | + * | |
| 1647 | + * With authentication this copies a hash, otherwise does nothing. | |
| 1648 | + */ | |
| 1649 | +static inline void ubifs_copy_hash(const struct ubifs_info *c, const u8 *from, | |
| 1650 | + u8 *to) | |
| 1651 | +{ | |
| 1652 | + if (ubifs_authenticated(c)) | |
| 1653 | + memcpy(to, from, c->hash_len); | |
| 1654 | +} | |
| 1655 | + | |
| 1656 | +int __ubifs_node_insert_hmac(const struct ubifs_info *c, void *buf, | |
| 1657 | + int len, int ofs_hmac); | |
| 1658 | +static inline int ubifs_node_insert_hmac(const struct ubifs_info *c, void *buf, | |
| 1659 | + int len, int ofs_hmac) | |
| 1660 | +{ | |
| 1661 | + if (ubifs_authenticated(c)) | |
| 1662 | + return __ubifs_node_insert_hmac(c, buf, len, ofs_hmac); | |
| 1663 | + else | |
| 1664 | + return 0; | |
| 1665 | +} | |
| 1666 | + | |
| 1667 | +int __ubifs_node_verify_hmac(const struct ubifs_info *c, const void *buf, | |
| 1668 | + int len, int ofs_hmac); | |
| 1669 | +static inline int ubifs_node_verify_hmac(const struct ubifs_info *c, | |
| 1670 | + const void *buf, int len, int ofs_hmac) | |
| 1671 | +{ | |
| 1672 | + if (ubifs_authenticated(c)) | |
| 1673 | + return __ubifs_node_verify_hmac(c, buf, len, ofs_hmac); | |
| 1674 | + else | |
| 1675 | + return 0; | |
| 1676 | +} | |
| 1677 | + | |
| 1678 | +/** | |
| 1679 | + * ubifs_auth_node_sz - returns the size of an authentication node | |
| 1680 | + * @c: UBIFS file-system description object | |
| 1681 | + * | |
| 1682 | + * This function returns the size of an authentication node which can | |
| 1683 | + * be 0 for unauthenticated filesystems or the real size of an auth node | |
| 1684 | + * authentication is enabled. | |
| 1685 | + */ | |
| 1686 | +static inline int ubifs_auth_node_sz(const struct ubifs_info *c) | |
| 1687 | +{ | |
| 1688 | + if (ubifs_authenticated(c)) | |
| 1689 | + return sizeof(struct ubifs_auth_node) + c->hmac_desc_len; | |
| 1690 | + else | |
| 1691 | + return 0; | |
| 1692 | +} | |
| 1693 | + | |
| 1694 | +int ubifs_hmac_wkm(struct ubifs_info *c, u8 *hmac); | |
| 1695 | + | |
| 1696 | +int __ubifs_shash_copy_state(const struct ubifs_info *c, struct shash_desc *src, | |
| 1697 | + struct shash_desc *target); | |
| 1698 | +static inline int ubifs_shash_copy_state(const struct ubifs_info *c, | |
| 1699 | + struct shash_desc *src, | |
| 1700 | + struct shash_desc *target) | |
| 1701 | +{ | |
| 1702 | + if (ubifs_authenticated(c)) | |
| 1703 | + return __ubifs_shash_copy_state(c, src, target); | |
| 1704 | + else | |
| 1705 | + return 0; | |
| 1706 | +} | |
| 1707 | + | |
| 1474 | 1708 | /* io.c */ |
| 1475 | 1709 | void ubifs_ro_mode(struct ubifs_info *c, int err); |
| 1476 | 1710 | int ubifs_leb_read(const struct ubifs_info *c, int lnum, void *buf, int offs, |
| @@ -1490,9 +1724,15 @@ int ubifs_read_node_wbuf(struct ubifs_wbuf *wbuf, void *buf, int type, int len, · 13 unmodified lines | ||
| 1490 | 1724 | int lnum, int offs); |
| 1491 | 1725 | int ubifs_write_node(struct ubifs_info *c, void *node, int len, int lnum, |
| 1492 | 1726 | int offs); |
| 1727 | +int ubifs_write_node_hmac(struct ubifs_info *c, void *buf, int len, int lnum, | |
| 1728 | + int offs, int hmac_offs); | |
| 1493 | 1729 | int ubifs_check_node(const struct ubifs_info *c, const void *buf, int lnum, |
| 1494 | 1730 | int offs, int quiet, int must_chk_crc); |
| 1731 | +void ubifs_init_node(struct ubifs_info *c, void *buf, int len, int pad); | |
| 1732 | +void ubifs_crc_node(struct ubifs_info *c, void *buf, int len); | |
| 1495 | 1733 | void ubifs_prepare_node(struct ubifs_info *c, void *buf, int len, int pad); |
| 1734 | +int ubifs_prepare_node_hmac(struct ubifs_info *c, void *node, int len, | |
| 1735 | + int hmac_offs, int pad); | |
| 1496 | 1736 | void ubifs_prep_grp_node(struct ubifs_info *c, void *node, int len, int last); |
| 1497 | 1737 | int ubifs_io_init(struct ubifs_info *c); |
| 1498 | 1738 | void ubifs_pad(const struct ubifs_info *c, void *buf, int pad); |
| @@ -1592,11 +1832,12 @@ int ubifs_tnc_lookup_dh(struct ubifs_info *c, const union ubifs_key *key, · 93 unmodified lines | ||
| 1592 | 1832 | int ubifs_tnc_locate(struct ubifs_info *c, const union ubifs_key *key, |
| 1593 | 1833 | void *node, int *lnum, int *offs); |
| 1594 | 1834 | int ubifs_tnc_add(struct ubifs_info *c, const union ubifs_key *key, int lnum, |
| 1595 | − int offs, int len); | |
| 1835 | + int offs, int len, const u8 *hash); | |
| 1596 | 1836 | int ubifs_tnc_replace(struct ubifs_info *c, const union ubifs_key *key, |
| 1597 | 1837 | int old_lnum, int old_offs, int lnum, int offs, int len); |
| 1598 | 1838 | int ubifs_tnc_add_nm(struct ubifs_info *c, const union ubifs_key *key, |
| 1599 | − int lnum, int offs, int len, const struct fscrypt_name *nm); | |
| 1839 | + int lnum, int offs, int len, const u8 *hash, | |
| 1840 | + const struct fscrypt_name *nm); | |
| 1600 | 1841 | int ubifs_tnc_remove(struct ubifs_info *c, const union ubifs_key *key); |
| 1601 | 1842 | int ubifs_tnc_remove_nm(struct ubifs_info *c, const union ubifs_key *key, |
| 1602 | 1843 | const struct fscrypt_name *nm); |
| @@ -1659,12 +1900,12 @@ int ubifs_gc_should_commit(struct ubifs_info *c); · 56 unmodified lines | ||
| 1659 | 1900 | void ubifs_wait_for_commit(struct ubifs_info *c); |
| 1660 | 1901 | |
| 1661 | 1902 | /* master.c */ |
| 1903 | +int ubifs_compare_master_node(struct ubifs_info *c, void *m1, void *m2); | |
| 1662 | 1904 | int ubifs_read_master(struct ubifs_info *c); |
| 1663 | 1905 | int ubifs_write_master(struct ubifs_info *c); |
| 1664 | 1906 | |
| 1665 | 1907 | /* sb.c */ |
| 1666 | 1908 | int ubifs_read_superblock(struct ubifs_info *c); |
| 1667 | −struct ubifs_sb_node *ubifs_read_sb_node(struct ubifs_info *c); | |
| 1668 | 1909 | int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup); |
| 1669 | 1910 | int ubifs_fixup_free_space(struct ubifs_info *c); |
| 1670 | 1911 | int ubifs_enable_encryption(struct ubifs_info *c); |
| @@ -1693,7 +1934,7 @@ int ubifs_clear_orphans(struct ubifs_info *c); · 22 unmodified lines | ||
| 1693 | 1934 | /* lpt.c */ |
| 1694 | 1935 | int ubifs_calc_lpt_geom(struct ubifs_info *c); |
| 1695 | 1936 | int ubifs_create_dflt_lpt(struct ubifs_info *c, int *main_lebs, int lpt_first, |
| 1696 | − int *lpt_lebs, int *big_lpt); | |
| 1937 | + int *lpt_lebs, int *big_lpt, u8 *hash); | |
| 1697 | 1938 | int ubifs_lpt_init(struct ubifs_info *c, int rd, int wr); |
| 1698 | 1939 | struct ubifs_lprops *ubifs_lpt_lookup(struct ubifs_info *c, int lnum); |
| 1699 | 1940 | struct ubifs_lprops *ubifs_lpt_lookup_dirty(struct ubifs_info *c, int lnum); |
| @@ -1712,6 +1953,7 @@ struct ubifs_pnode *ubifs_get_pnode(struct ubifs_info *c, · 12 unmodified lines | ||
| 1712 | 1953 | struct ubifs_nnode *parent, int iip); |
| 1713 | 1954 | struct ubifs_nnode *ubifs_get_nnode(struct ubifs_info *c, |
| 1714 | 1955 | struct ubifs_nnode *parent, int iip); |
| 1956 | +struct ubifs_pnode *ubifs_pnode_lookup(struct ubifs_info *c, int i); | |
| 1715 | 1957 | int ubifs_read_nnode(struct ubifs_info *c, struct ubifs_nnode *parent, int iip); |
| 1716 | 1958 | void ubifs_add_lpt_dirt(struct ubifs_info *c, int lnum, int dirty); |
| 1717 | 1959 | void ubifs_add_nnode_dirt(struct ubifs_info *c, struct ubifs_nnode *nnode); |
| @@ -1720,6 +1962,7 @@ struct ubifs_nnode *ubifs_first_nnode(struct ubifs_info *c, int *hght); · 2 unmodified lines | ||
| 1720 | 1962 | /* Needed only in debugging code in lpt_commit.c */ |
| 1721 | 1963 | int ubifs_unpack_nnode(const struct ubifs_info *c, void *buf, |
| 1722 | 1964 | struct ubifs_nnode *nnode); |
| 1965 | +int ubifs_lpt_calc_hash(struct ubifs_info *c, u8 *hash); | |
| 1723 | 1966 | |
| 1724 | 1967 | /* lpt_commit.c */ |
| 1725 | 1968 | int ubifs_lpt_start_commit(struct ubifs_info *c); |
| @@ -1807,7 +2050,7 @@ int ubifs_clean_lebs(struct ubifs_info *c, void *sbuf); · 81 unmodified lines | ||
| 1807 | 2050 | int ubifs_rcvry_gc_commit(struct ubifs_info *c); |
| 1808 | 2051 | int ubifs_recover_size_accum(struct ubifs_info *c, union ubifs_key *key, |
| 1809 | 2052 | int deletion, loff_t new_size); |
| 1810 | −int ubifs_recover_size(struct ubifs_info *c); | |
| 2053 | +int ubifs_recover_size(struct ubifs_info *c, bool in_place); | |
| 1811 | 2054 | void ubifs_destroy_size_tree(struct ubifs_info *c); |
| 1812 | 2055 | |
| 1813 | 2056 | /* ioctl.c */ |