@@ -21,6 +21,12 @@ MODULE_AUTHOR("Jan Kara");
21
21
MODULE_DESCRIPTION ("Quota trie support" );
22
22
MODULE_LICENSE ("GPL" );
23
23
24
+ /*
25
+ * Maximum quota tree depth we support. Only to limit recursion when working
26
+ * with the tree.
27
+ */
28
+ #define MAX_QTREE_DEPTH 6
29
+
24
30
#define __QUOTA_QT_PARANOIA
25
31
26
32
static int __get_index (struct qtree_mem_dqinfo * info , qid_t id , int depth )
@@ -327,27 +333,36 @@ static uint find_free_dqentry(struct qtree_mem_dqinfo *info,
327
333
328
334
/* Insert reference to structure into the trie */
329
335
static int do_insert_tree (struct qtree_mem_dqinfo * info , struct dquot * dquot ,
330
- uint * treeblk , int depth )
336
+ uint * blks , int depth )
331
337
{
332
338
char * buf = kmalloc (info -> dqi_usable_bs , GFP_KERNEL );
333
339
int ret = 0 , newson = 0 , newact = 0 ;
334
340
__le32 * ref ;
335
341
uint newblk ;
342
+ int i ;
336
343
337
344
if (!buf )
338
345
return - ENOMEM ;
339
- if (!* treeblk ) {
346
+ if (!blks [ depth ] ) {
340
347
ret = get_free_dqblk (info );
341
348
if (ret < 0 )
342
349
goto out_buf ;
343
- * treeblk = ret ;
350
+ for (i = 0 ; i < depth ; i ++ )
351
+ if (ret == blks [i ]) {
352
+ quota_error (dquot -> dq_sb ,
353
+ "Free block already used in tree: block %u" ,
354
+ ret );
355
+ ret = - EIO ;
356
+ goto out_buf ;
357
+ }
358
+ blks [depth ] = ret ;
344
359
memset (buf , 0 , info -> dqi_usable_bs );
345
360
newact = 1 ;
346
361
} else {
347
- ret = read_blk (info , * treeblk , buf );
362
+ ret = read_blk (info , blks [ depth ] , buf );
348
363
if (ret < 0 ) {
349
364
quota_error (dquot -> dq_sb , "Can't read tree quota "
350
- "block %u" , * treeblk );
365
+ "block %u" , blks [ depth ] );
351
366
goto out_buf ;
352
367
}
353
368
}
@@ -357,8 +372,20 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
357
372
info -> dqi_blocks - 1 );
358
373
if (ret )
359
374
goto out_buf ;
360
- if (!newblk )
375
+ if (!newblk ) {
361
376
newson = 1 ;
377
+ } else {
378
+ for (i = 0 ; i <= depth ; i ++ )
379
+ if (newblk == blks [i ]) {
380
+ quota_error (dquot -> dq_sb ,
381
+ "Cycle in quota tree detected: block %u index %u" ,
382
+ blks [depth ],
383
+ get_index (info , dquot -> dq_id , depth ));
384
+ ret = - EIO ;
385
+ goto out_buf ;
386
+ }
387
+ }
388
+ blks [depth + 1 ] = newblk ;
362
389
if (depth == info -> dqi_qtree_depth - 1 ) {
363
390
#ifdef __QUOTA_QT_PARANOIA
364
391
if (newblk ) {
@@ -370,16 +397,16 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
370
397
goto out_buf ;
371
398
}
372
399
#endif
373
- newblk = find_free_dqentry (info , dquot , & ret );
400
+ blks [ depth + 1 ] = find_free_dqentry (info , dquot , & ret );
374
401
} else {
375
- ret = do_insert_tree (info , dquot , & newblk , depth + 1 );
402
+ ret = do_insert_tree (info , dquot , blks , depth + 1 );
376
403
}
377
404
if (newson && ret >= 0 ) {
378
405
ref [get_index (info , dquot -> dq_id , depth )] =
379
- cpu_to_le32 (newblk );
380
- ret = write_blk (info , * treeblk , buf );
406
+ cpu_to_le32 (blks [ depth + 1 ] );
407
+ ret = write_blk (info , blks [ depth ] , buf );
381
408
} else if (newact && ret < 0 ) {
382
- put_free_dqblk (info , buf , * treeblk );
409
+ put_free_dqblk (info , buf , blks [ depth ] );
383
410
}
384
411
out_buf :
385
412
kfree (buf );
@@ -390,15 +417,19 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
390
417
static inline int dq_insert_tree (struct qtree_mem_dqinfo * info ,
391
418
struct dquot * dquot )
392
419
{
393
- int tmp = QT_TREEOFF ;
420
+ uint blks [ MAX_QTREE_DEPTH ] = { QT_TREEOFF } ;
394
421
395
422
#ifdef __QUOTA_QT_PARANOIA
396
423
if (info -> dqi_blocks <= QT_TREEOFF ) {
397
424
quota_error (dquot -> dq_sb , "Quota tree root isn't allocated!" );
398
425
return - EIO ;
399
426
}
400
427
#endif
401
- return do_insert_tree (info , dquot , & tmp , 0 );
428
+ if (info -> dqi_qtree_depth >= MAX_QTREE_DEPTH ) {
429
+ quota_error (dquot -> dq_sb , "Quota tree depth too big!" );
430
+ return - EIO ;
431
+ }
432
+ return do_insert_tree (info , dquot , blks , 0 );
402
433
}
403
434
404
435
/*
@@ -511,19 +542,20 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
511
542
512
543
/* Remove reference to dquot from tree */
513
544
static int remove_tree (struct qtree_mem_dqinfo * info , struct dquot * dquot ,
514
- uint * blk , int depth )
545
+ uint * blks , int depth )
515
546
{
516
547
char * buf = kmalloc (info -> dqi_usable_bs , GFP_KERNEL );
517
548
int ret = 0 ;
518
549
uint newblk ;
519
550
__le32 * ref = (__le32 * )buf ;
551
+ int i ;
520
552
521
553
if (!buf )
522
554
return - ENOMEM ;
523
- ret = read_blk (info , * blk , buf );
555
+ ret = read_blk (info , blks [ depth ] , buf );
524
556
if (ret < 0 ) {
525
557
quota_error (dquot -> dq_sb , "Can't read quota data block %u" ,
526
- * blk );
558
+ blks [ depth ] );
527
559
goto out_buf ;
528
560
}
529
561
newblk = le32_to_cpu (ref [get_index (info , dquot -> dq_id , depth )]);
@@ -532,29 +564,38 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
532
564
if (ret )
533
565
goto out_buf ;
534
566
567
+ for (i = 0 ; i <= depth ; i ++ )
568
+ if (newblk == blks [i ]) {
569
+ quota_error (dquot -> dq_sb ,
570
+ "Cycle in quota tree detected: block %u index %u" ,
571
+ blks [depth ],
572
+ get_index (info , dquot -> dq_id , depth ));
573
+ ret = - EIO ;
574
+ goto out_buf ;
575
+ }
535
576
if (depth == info -> dqi_qtree_depth - 1 ) {
536
577
ret = free_dqentry (info , dquot , newblk );
537
- newblk = 0 ;
578
+ blks [ depth + 1 ] = 0 ;
538
579
} else {
539
- ret = remove_tree (info , dquot , & newblk , depth + 1 );
580
+ blks [depth + 1 ] = newblk ;
581
+ ret = remove_tree (info , dquot , blks , depth + 1 );
540
582
}
541
- if (ret >= 0 && !newblk ) {
542
- int i ;
583
+ if (ret >= 0 && !blks [depth + 1 ]) {
543
584
ref [get_index (info , dquot -> dq_id , depth )] = cpu_to_le32 (0 );
544
585
/* Block got empty? */
545
586
for (i = 0 ; i < (info -> dqi_usable_bs >> 2 ) && !ref [i ]; i ++ )
546
587
;
547
588
/* Don't put the root block into the free block list */
548
589
if (i == (info -> dqi_usable_bs >> 2 )
549
- && * blk != QT_TREEOFF ) {
550
- put_free_dqblk (info , buf , * blk );
551
- * blk = 0 ;
590
+ && blks [ depth ] != QT_TREEOFF ) {
591
+ put_free_dqblk (info , buf , blks [ depth ] );
592
+ blks [ depth ] = 0 ;
552
593
} else {
553
- ret = write_blk (info , * blk , buf );
594
+ ret = write_blk (info , blks [ depth ] , buf );
554
595
if (ret < 0 )
555
596
quota_error (dquot -> dq_sb ,
556
597
"Can't write quota tree block %u" ,
557
- * blk );
598
+ blks [ depth ] );
558
599
}
559
600
}
560
601
out_buf :
@@ -565,11 +606,15 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
565
606
/* Delete dquot from tree */
566
607
int qtree_delete_dquot (struct qtree_mem_dqinfo * info , struct dquot * dquot )
567
608
{
568
- uint tmp = QT_TREEOFF ;
609
+ uint blks [ MAX_QTREE_DEPTH ] = { QT_TREEOFF } ;
569
610
570
611
if (!dquot -> dq_off ) /* Even not allocated? */
571
612
return 0 ;
572
- return remove_tree (info , dquot , & tmp , 0 );
613
+ if (info -> dqi_qtree_depth >= MAX_QTREE_DEPTH ) {
614
+ quota_error (dquot -> dq_sb , "Quota tree depth too big!" );
615
+ return - EIO ;
616
+ }
617
+ return remove_tree (info , dquot , blks , 0 );
573
618
}
574
619
EXPORT_SYMBOL (qtree_delete_dquot );
575
620
@@ -613,18 +658,20 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
613
658
614
659
/* Find entry for given id in the tree */
615
660
static loff_t find_tree_dqentry (struct qtree_mem_dqinfo * info ,
616
- struct dquot * dquot , uint blk , int depth )
661
+ struct dquot * dquot , uint * blks , int depth )
617
662
{
618
663
char * buf = kmalloc (info -> dqi_usable_bs , GFP_KERNEL );
619
664
loff_t ret = 0 ;
620
665
__le32 * ref = (__le32 * )buf ;
666
+ uint blk ;
667
+ int i ;
621
668
622
669
if (!buf )
623
670
return - ENOMEM ;
624
- ret = read_blk (info , blk , buf );
671
+ ret = read_blk (info , blks [ depth ] , buf );
625
672
if (ret < 0 ) {
626
673
quota_error (dquot -> dq_sb , "Can't read quota tree block %u" ,
627
- blk );
674
+ blks [ depth ] );
628
675
goto out_buf ;
629
676
}
630
677
ret = 0 ;
@@ -636,8 +683,19 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
636
683
if (ret )
637
684
goto out_buf ;
638
685
686
+ /* Check for cycles in the tree */
687
+ for (i = 0 ; i <= depth ; i ++ )
688
+ if (blk == blks [i ]) {
689
+ quota_error (dquot -> dq_sb ,
690
+ "Cycle in quota tree detected: block %u index %u" ,
691
+ blks [depth ],
692
+ get_index (info , dquot -> dq_id , depth ));
693
+ ret = - EIO ;
694
+ goto out_buf ;
695
+ }
696
+ blks [depth + 1 ] = blk ;
639
697
if (depth < info -> dqi_qtree_depth - 1 )
640
- ret = find_tree_dqentry (info , dquot , blk , depth + 1 );
698
+ ret = find_tree_dqentry (info , dquot , blks , depth + 1 );
641
699
else
642
700
ret = find_block_dqentry (info , dquot , blk );
643
701
out_buf :
@@ -649,7 +707,13 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
649
707
static inline loff_t find_dqentry (struct qtree_mem_dqinfo * info ,
650
708
struct dquot * dquot )
651
709
{
652
- return find_tree_dqentry (info , dquot , QT_TREEOFF , 0 );
710
+ uint blks [MAX_QTREE_DEPTH ] = { QT_TREEOFF };
711
+
712
+ if (info -> dqi_qtree_depth >= MAX_QTREE_DEPTH ) {
713
+ quota_error (dquot -> dq_sb , "Quota tree depth too big!" );
714
+ return - EIO ;
715
+ }
716
+ return find_tree_dqentry (info , dquot , blks , 0 );
653
717
}
654
718
655
719
int qtree_read_dquot (struct qtree_mem_dqinfo * info , struct dquot * dquot )
0 commit comments