1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * 4 * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved. 5 * 6 */ 7 8 #include <linux/fs.h> 9 10 #include "debug.h" 11 #include "ntfs.h" 12 #include "ntfs_fs.h" 13 14 /* 15 * al_is_valid_le 16 * 17 * Return: True if @le is valid. 18 */ 19 static inline bool al_is_valid_le(const struct ntfs_inode *ni, 20 struct ATTR_LIST_ENTRY *le) 21 { 22 ni = ni->base; 23 if (!le || !ni->attr_list.le || !ni->attr_list.size) 24 return false; 25 26 return PtrOffset(ni->attr_list.le, le) + le16_to_cpu(le->size) <= 27 ni->attr_list.size; 28 } 29 30 void al_destroy(struct ntfs_inode *ni) 31 { 32 ni = ni->base; 33 run_close(&ni->attr_list.run); 34 kvfree(ni->attr_list.le); 35 ni->attr_list.le = NULL; 36 ni->attr_list.size = 0; 37 ni->attr_list.dirty = false; 38 } 39 40 /* 41 * ntfs_load_attr_list 42 * 43 * This method makes sure that the ATTRIB list, if present, 44 * has been properly set up. 45 */ 46 int ntfs_load_attr_list(struct ntfs_inode *ni, struct ATTRIB *attr) 47 { 48 int err; 49 size_t lsize; 50 void *le = NULL; 51 52 ni = ni->base; 53 if (ni->attr_list.size) 54 return 0; 55 56 if (!attr->non_res) { 57 lsize = le32_to_cpu(attr->res.data_size); 58 if (!lsize) { 59 err = -EINVAL; 60 goto out; 61 } 62 63 /* attr is resident: lsize < record_size (1K or 4K) */ 64 le = kvmalloc(al_aligned(lsize), GFP_KERNEL); 65 if (!le) { 66 err = -ENOMEM; 67 goto out; 68 } 69 memcpy(le, resident_data(attr), lsize); 70 } else if (attr->nres.svcn) { 71 err = -EINVAL; 72 goto out; 73 } else { 74 u16 run_off = le16_to_cpu(attr->nres.run_off); 75 76 lsize = le64_to_cpu(attr->nres.data_size); 77 if (!lsize) { 78 err = -EINVAL; 79 goto out; 80 } 81 82 run_init(&ni->attr_list.run); 83 84 if (run_off > le32_to_cpu(attr->size)) { 85 err = -EINVAL; 86 goto out; 87 } 88 89 err = run_unpack_ex(&ni->attr_list.run, ni->mi.sbi, ni->mi.rno, 90 0, le64_to_cpu(attr->nres.evcn), 0, 91 Add2Ptr(attr, run_off), 92 le32_to_cpu(attr->size) - run_off); 93 if (err < 0) 94 goto out; 95 96 /* attr is nonresident. 97 * The worst case: 98 * 1T (2^40) extremely fragmented file. 99 * cluster = 4K (2^12) => 2^28 fragments 100 * 2^9 fragments per one record => 2^19 records 101 * 2^5 bytes of ATTR_LIST_ENTRY per one record => 2^24 bytes. 102 * 103 * the result is 16M bytes per attribute list. 104 * Use kvmalloc to allocate in range [several Kbytes - dozen Mbytes] 105 */ 106 le = kvmalloc(al_aligned(lsize), GFP_KERNEL); 107 if (!le) { 108 err = -ENOMEM; 109 goto out; 110 } 111 112 err = ntfs_read_run_nb(ni->mi.sbi, &ni->attr_list.run, 0, le, 113 lsize, NULL); 114 if (err) 115 goto out; 116 } 117 118 ni->attr_list.size = lsize; 119 ni->attr_list.le = le; 120 121 return 0; 122 123 out: 124 ni->attr_list.le = le; 125 al_destroy(ni); 126 127 return err; 128 } 129 130 /* 131 * al_enumerate 132 * 133 * Return: 134 * * The next list le. 135 * * If @le is NULL then return the first le. 136 */ 137 struct ATTR_LIST_ENTRY *al_enumerate(struct ntfs_inode *ni, 138 struct ATTR_LIST_ENTRY *le) 139 { 140 size_t off; 141 u16 sz; 142 const unsigned le_min_size = le_size(0); 143 144 if (!le) { 145 le = ni->attr_list.le; 146 } else { 147 sz = le16_to_cpu(le->size); 148 if (sz < le_min_size) { 149 /* Impossible 'cause we should not return such le. */ 150 return NULL; 151 } 152 le = Add2Ptr(le, sz); 153 } 154 155 /* Check boundary. */ 156 off = PtrOffset(ni->attr_list.le, le); 157 if (off + le_min_size > ni->attr_list.size) { 158 /* The regular end of list. */ 159 return NULL; 160 } 161 162 sz = le16_to_cpu(le->size); 163 164 /* Check le for errors. */ 165 if (sz < le_min_size || off + sz > ni->attr_list.size || 166 sz < le->name_off + le->name_len * sizeof(short)) { 167 return NULL; 168 } 169 170 return le; 171 } 172 173 /* 174 * al_find_le 175 * 176 * Find the first le in the list which matches type, name and VCN. 177 * 178 * Return: NULL if not found. 179 */ 180 struct ATTR_LIST_ENTRY *al_find_le(struct ntfs_inode *ni, 181 struct ATTR_LIST_ENTRY *le, 182 const struct ATTRIB *attr) 183 { 184 CLST svcn = attr_svcn(attr); 185 186 return al_find_ex(ni, le, attr->type, attr_name(attr), attr->name_len, 187 &svcn); 188 } 189 190 /* 191 * al_find_ex 192 * 193 * Find the first le in the list which matches type, name and VCN. 194 * 195 * Return: NULL if not found. 196 */ 197 struct ATTR_LIST_ENTRY *al_find_ex(struct ntfs_inode *ni, 198 struct ATTR_LIST_ENTRY *le, 199 enum ATTR_TYPE type, const __le16 *name, 200 u8 name_len, const CLST *vcn) 201 { 202 struct ATTR_LIST_ENTRY *ret = NULL; 203 u32 type_in = le32_to_cpu(type); 204 205 ni = ni->base; 206 while ((le = al_enumerate(ni, le))) { 207 u64 le_vcn; 208 int diff = le32_to_cpu(le->type) - type_in; 209 210 /* List entries are sorted by type, name and VCN. */ 211 if (diff < 0) 212 continue; 213 214 if (diff > 0) 215 return ret; 216 217 if (le->name_len != name_len) 218 continue; 219 220 le_vcn = le64_to_cpu(le->vcn); 221 if (!le_vcn) { 222 /* 223 * Compare entry names only for entry with vcn == 0. 224 */ 225 diff = ntfs_cmp_names(le_name(le), name_len, name, 226 name_len, ni->mi.sbi->upcase, 227 true); 228 if (diff < 0) 229 continue; 230 231 if (diff > 0) 232 return ret; 233 } 234 235 if (!vcn) 236 return le; 237 238 if (*vcn == le_vcn) 239 return le; 240 241 if (*vcn < le_vcn) 242 return ret; 243 244 ret = le; 245 } 246 247 return ret; 248 } 249 250 /* 251 * al_find_le_to_insert 252 * 253 * Find the first list entry which matches type, name and VCN. 254 */ 255 static struct ATTR_LIST_ENTRY *al_find_le_to_insert(struct ntfs_inode *ni, 256 enum ATTR_TYPE type, 257 const __le16 *name, 258 u8 name_len, CLST vcn) 259 { 260 struct ATTR_LIST_ENTRY *le = NULL, *prev; 261 u32 type_in = le32_to_cpu(type); 262 263 ni = ni->base; 264 /* List entries are sorted by type, name and VCN. */ 265 while ((le = al_enumerate(ni, prev = le))) { 266 int diff = le32_to_cpu(le->type) - type_in; 267 268 if (diff < 0) 269 continue; 270 271 if (diff > 0) 272 return le; 273 274 if (!le->vcn) { 275 /* 276 * Compare entry names only for entry with vcn == 0. 277 */ 278 diff = ntfs_cmp_names(le_name(le), le->name_len, name, 279 name_len, ni->mi.sbi->upcase, 280 true); 281 if (diff < 0) 282 continue; 283 284 if (diff > 0) 285 return le; 286 } 287 288 if (le64_to_cpu(le->vcn) >= vcn) 289 return le; 290 } 291 292 return prev ? Add2Ptr(prev, le16_to_cpu(prev->size)) : ni->attr_list.le; 293 } 294 295 /* 296 * al_add_le 297 * 298 * Add an "attribute list entry" to the list. 299 */ 300 int al_add_le(struct ntfs_inode *ni, enum ATTR_TYPE type, const __le16 *name, 301 u8 name_len, CLST svcn, __le16 id, const struct MFT_REF *ref, 302 struct ATTR_LIST_ENTRY **new_le) 303 { 304 int err; 305 struct ATTRIB *attr; 306 struct ATTR_LIST_ENTRY *le; 307 size_t off; 308 u16 sz; 309 size_t asize, new_asize, old_size; 310 u64 new_size; 311 typeof(ni->attr_list) *al = &ni->attr_list; 312 313 ni = ni->base; 314 /* 315 * Compute the size of the new 'le' 316 */ 317 sz = le_size(name_len); 318 old_size = al->size; 319 new_size = old_size + sz; 320 asize = al_aligned(old_size); 321 new_asize = al_aligned(new_size); 322 323 /* Scan forward to the point at which the new 'le' should be inserted. */ 324 le = al_find_le_to_insert(ni, type, name, name_len, svcn); 325 off = PtrOffset(al->le, le); 326 327 if (new_size > asize) { 328 void *ptr = kmalloc(new_asize, GFP_NOFS); 329 330 if (!ptr) 331 return -ENOMEM; 332 333 memcpy(ptr, al->le, off); 334 memcpy(Add2Ptr(ptr, off + sz), le, old_size - off); 335 le = Add2Ptr(ptr, off); 336 kvfree(al->le); 337 al->le = ptr; 338 } else { 339 memmove(Add2Ptr(le, sz), le, old_size - off); 340 } 341 *new_le = le; 342 343 al->size = new_size; 344 345 le->type = type; 346 le->size = cpu_to_le16(sz); 347 le->name_len = name_len; 348 le->name_off = offsetof(struct ATTR_LIST_ENTRY, name); 349 le->vcn = cpu_to_le64(svcn); 350 le->ref = *ref; 351 le->id = id; 352 memcpy(le->name, name, sizeof(short) * name_len); 353 354 err = attr_set_size_ex(ni, ATTR_LIST, NULL, 0, &al->run, new_size, 355 &new_size, true, &attr, false); 356 if (err) { 357 /* Undo memmove above. */ 358 memmove(le, Add2Ptr(le, sz), old_size - off); 359 al->size = old_size; 360 return err; 361 } 362 363 al->dirty = true; 364 365 if (attr && attr->non_res) { 366 err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le, 367 al->size, 0); 368 if (err) 369 return err; 370 al->dirty = false; 371 } 372 373 return 0; 374 } 375 376 /* 377 * al_remove_le - Remove @le from attribute list. 378 */ 379 bool al_remove_le(struct ntfs_inode *ni, struct ATTR_LIST_ENTRY *le) 380 { 381 u16 size; 382 size_t off; 383 typeof(ni->attr_list) *al; 384 385 ni = ni->base; 386 al = &ni->attr_list; 387 if (!al_is_valid_le(ni, le)) 388 return false; 389 390 /* Save on stack the size of 'le' */ 391 size = le16_to_cpu(le->size); 392 off = PtrOffset(al->le, le); 393 394 memmove(le, Add2Ptr(le, size), al->size - (off + size)); 395 396 al->size -= size; 397 al->dirty = true; 398 399 return true; 400 } 401 402 int al_update(struct ntfs_inode *ni, int sync) 403 { 404 int err; 405 struct ATTRIB *attr; 406 typeof(ni->attr_list) *al; 407 408 ni = ni->base; 409 al = &ni->attr_list; 410 411 if (!al->dirty || !al->size) 412 return 0; 413 414 /* 415 * Attribute list increased on demand in al_add_le. 416 * Attribute list decreased here. 417 */ 418 err = attr_set_size_ex(ni, ATTR_LIST, NULL, 0, &al->run, al->size, NULL, 419 false, &attr, false); 420 if (err) 421 goto out; 422 423 if (!attr->non_res) { 424 memcpy(resident_data(attr), al->le, al->size); 425 } else { 426 err = ntfs_sb_write_run(ni->mi.sbi, &al->run, 0, al->le, 427 al->size, sync); 428 if (err) 429 goto out; 430 431 attr->nres.valid_size = attr->nres.data_size; 432 } 433 434 ni->mi.dirty = true; 435 al->dirty = false; 436 437 out: 438 return err; 439 } 440