@@ -21,6 +21,12 @@ MODULE_AUTHOR("Jan Kara");
2121MODULE_DESCRIPTION ("Quota trie support" );
2222MODULE_LICENSE ("GPL" );
2323
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+
2430#define __QUOTA_QT_PARANOIA
2531
2632static 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,
327333
328334/* Insert reference to structure into the trie */
329335static int do_insert_tree (struct qtree_mem_dqinfo * info , struct dquot * dquot ,
330- uint * treeblk , int depth )
336+ uint * blks , int depth )
331337{
332338 char * buf = kmalloc (info -> dqi_usable_bs , GFP_KERNEL );
333339 int ret = 0 , newson = 0 , newact = 0 ;
334340 __le32 * ref ;
335341 uint newblk ;
342+ int i ;
336343
337344 if (!buf )
338345 return - ENOMEM ;
339- if (!* treeblk ) {
346+ if (!blks [ depth ] ) {
340347 ret = get_free_dqblk (info );
341348 if (ret < 0 )
342349 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 ;
344359 memset (buf , 0 , info -> dqi_usable_bs );
345360 newact = 1 ;
346361 } else {
347- ret = read_blk (info , * treeblk , buf );
362+ ret = read_blk (info , blks [ depth ] , buf );
348363 if (ret < 0 ) {
349364 quota_error (dquot -> dq_sb , "Can't read tree quota "
350- "block %u" , * treeblk );
365+ "block %u" , blks [ depth ] );
351366 goto out_buf ;
352367 }
353368 }
@@ -357,8 +372,20 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
357372 info -> dqi_blocks - 1 );
358373 if (ret )
359374 goto out_buf ;
360- if (!newblk )
375+ if (!newblk ) {
361376 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 ;
362389 if (depth == info -> dqi_qtree_depth - 1 ) {
363390#ifdef __QUOTA_QT_PARANOIA
364391 if (newblk ) {
@@ -370,16 +397,16 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
370397 goto out_buf ;
371398 }
372399#endif
373- newblk = find_free_dqentry (info , dquot , & ret );
400+ blks [ depth + 1 ] = find_free_dqentry (info , dquot , & ret );
374401 } else {
375- ret = do_insert_tree (info , dquot , & newblk , depth + 1 );
402+ ret = do_insert_tree (info , dquot , blks , depth + 1 );
376403 }
377404 if (newson && ret >= 0 ) {
378405 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 );
381408 } else if (newact && ret < 0 ) {
382- put_free_dqblk (info , buf , * treeblk );
409+ put_free_dqblk (info , buf , blks [ depth ] );
383410 }
384411out_buf :
385412 kfree (buf );
@@ -390,15 +417,19 @@ static int do_insert_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
390417static inline int dq_insert_tree (struct qtree_mem_dqinfo * info ,
391418 struct dquot * dquot )
392419{
393- int tmp = QT_TREEOFF ;
420+ uint blks [ MAX_QTREE_DEPTH ] = { QT_TREEOFF } ;
394421
395422#ifdef __QUOTA_QT_PARANOIA
396423 if (info -> dqi_blocks <= QT_TREEOFF ) {
397424 quota_error (dquot -> dq_sb , "Quota tree root isn't allocated!" );
398425 return - EIO ;
399426 }
400427#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 );
402433}
403434
404435/*
@@ -511,19 +542,20 @@ static int free_dqentry(struct qtree_mem_dqinfo *info, struct dquot *dquot,
511542
512543/* Remove reference to dquot from tree */
513544static int remove_tree (struct qtree_mem_dqinfo * info , struct dquot * dquot ,
514- uint * blk , int depth )
545+ uint * blks , int depth )
515546{
516547 char * buf = kmalloc (info -> dqi_usable_bs , GFP_KERNEL );
517548 int ret = 0 ;
518549 uint newblk ;
519550 __le32 * ref = (__le32 * )buf ;
551+ int i ;
520552
521553 if (!buf )
522554 return - ENOMEM ;
523- ret = read_blk (info , * blk , buf );
555+ ret = read_blk (info , blks [ depth ] , buf );
524556 if (ret < 0 ) {
525557 quota_error (dquot -> dq_sb , "Can't read quota data block %u" ,
526- * blk );
558+ blks [ depth ] );
527559 goto out_buf ;
528560 }
529561 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,
532564 if (ret )
533565 goto out_buf ;
534566
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+ }
535576 if (depth == info -> dqi_qtree_depth - 1 ) {
536577 ret = free_dqentry (info , dquot , newblk );
537- newblk = 0 ;
578+ blks [ depth + 1 ] = 0 ;
538579 } else {
539- ret = remove_tree (info , dquot , & newblk , depth + 1 );
580+ blks [depth + 1 ] = newblk ;
581+ ret = remove_tree (info , dquot , blks , depth + 1 );
540582 }
541- if (ret >= 0 && !newblk ) {
542- int i ;
583+ if (ret >= 0 && !blks [depth + 1 ]) {
543584 ref [get_index (info , dquot -> dq_id , depth )] = cpu_to_le32 (0 );
544585 /* Block got empty? */
545586 for (i = 0 ; i < (info -> dqi_usable_bs >> 2 ) && !ref [i ]; i ++ )
546587 ;
547588 /* Don't put the root block into the free block list */
548589 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 ;
552593 } else {
553- ret = write_blk (info , * blk , buf );
594+ ret = write_blk (info , blks [ depth ] , buf );
554595 if (ret < 0 )
555596 quota_error (dquot -> dq_sb ,
556597 "Can't write quota tree block %u" ,
557- * blk );
598+ blks [ depth ] );
558599 }
559600 }
560601out_buf :
@@ -565,11 +606,15 @@ static int remove_tree(struct qtree_mem_dqinfo *info, struct dquot *dquot,
565606/* Delete dquot from tree */
566607int qtree_delete_dquot (struct qtree_mem_dqinfo * info , struct dquot * dquot )
567608{
568- uint tmp = QT_TREEOFF ;
609+ uint blks [ MAX_QTREE_DEPTH ] = { QT_TREEOFF } ;
569610
570611 if (!dquot -> dq_off ) /* Even not allocated? */
571612 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 );
573618}
574619EXPORT_SYMBOL (qtree_delete_dquot );
575620
@@ -613,18 +658,20 @@ static loff_t find_block_dqentry(struct qtree_mem_dqinfo *info,
613658
614659/* Find entry for given id in the tree */
615660static 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 )
617662{
618663 char * buf = kmalloc (info -> dqi_usable_bs , GFP_KERNEL );
619664 loff_t ret = 0 ;
620665 __le32 * ref = (__le32 * )buf ;
666+ uint blk ;
667+ int i ;
621668
622669 if (!buf )
623670 return - ENOMEM ;
624- ret = read_blk (info , blk , buf );
671+ ret = read_blk (info , blks [ depth ] , buf );
625672 if (ret < 0 ) {
626673 quota_error (dquot -> dq_sb , "Can't read quota tree block %u" ,
627- blk );
674+ blks [ depth ] );
628675 goto out_buf ;
629676 }
630677 ret = 0 ;
@@ -636,8 +683,19 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
636683 if (ret )
637684 goto out_buf ;
638685
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 ;
639697 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 );
641699 else
642700 ret = find_block_dqentry (info , dquot , blk );
643701out_buf :
@@ -649,7 +707,13 @@ static loff_t find_tree_dqentry(struct qtree_mem_dqinfo *info,
649707static inline loff_t find_dqentry (struct qtree_mem_dqinfo * info ,
650708 struct dquot * dquot )
651709{
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 );
653717}
654718
655719int qtree_read_dquot (struct qtree_mem_dqinfo * info , struct dquot * dquot )
0 commit comments