quota: do not allow setting of quota limits to too high values
authorAndrew Perepechko <andrew.perepechko@sun.com>
Mon, 28 Apr 2008 09:14:31 +0000 (02:14 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 28 Apr 2008 15:58:32 +0000 (08:58 -0700)
We should check whether quota limits set via Q_SETQUOTA are not exceeding
limits which quota format is able to handle.

Signed-off-by: Andrew Perepechko <andrew.perepechko@sun.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
fs/dquot.c
fs/quota_v1.c
fs/quota_v2.c
include/linux/quota.h

index 41b9dbd68b0e88e4a466685e1150e262e5d03c59..24eef582d2a0e937ec66e2c483670ab825020f63 100644 (file)
@@ -1709,10 +1709,19 @@ int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *d
 }
 
 /* Generic routine for setting common part of quota structure */
-static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
+static int do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
 {
        struct mem_dqblk *dm = &dquot->dq_dqb;
        int check_blim = 0, check_ilim = 0;
+       struct mem_dqinfo *dqi = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type];
+
+       if ((di->dqb_valid & QIF_BLIMITS &&
+            (di->dqb_bhardlimit > dqi->dqi_maxblimit ||
+             di->dqb_bsoftlimit > dqi->dqi_maxblimit)) ||
+           (di->dqb_valid & QIF_ILIMITS &&
+            (di->dqb_ihardlimit > dqi->dqi_maxilimit ||
+             di->dqb_isoftlimit > dqi->dqi_maxilimit)))
+               return -ERANGE;
 
        spin_lock(&dq_data_lock);
        if (di->dqb_valid & QIF_SPACE) {
@@ -1744,7 +1753,7 @@ static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
                        clear_bit(DQ_BLKS_B, &dquot->dq_flags);
                }
                else if (!(di->dqb_valid & QIF_BTIME))  /* Set grace only if user hasn't provided his own... */
-                       dm->dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace;
+                       dm->dqb_btime = get_seconds() + dqi->dqi_bgrace;
        }
        if (check_ilim) {
                if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) {
@@ -1752,7 +1761,7 @@ static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
                        clear_bit(DQ_INODES_B, &dquot->dq_flags);
                }
                else if (!(di->dqb_valid & QIF_ITIME))  /* Set grace only if user hasn't provided his own... */
-                       dm->dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace;
+                       dm->dqb_itime = get_seconds() + dqi->dqi_igrace;
        }
        if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit)
                clear_bit(DQ_FAKE_B, &dquot->dq_flags);
@@ -1760,21 +1769,24 @@ static void do_set_dqblk(struct dquot *dquot, struct if_dqblk *di)
                set_bit(DQ_FAKE_B, &dquot->dq_flags);
        spin_unlock(&dq_data_lock);
        mark_dquot_dirty(dquot);
+
+       return 0;
 }
 
 int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di)
 {
        struct dquot *dquot;
+       int rc;
 
        mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
        if (!(dquot = dqget(sb, id, type))) {
                mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
                return -ESRCH;
        }
-       do_set_dqblk(dquot, di);
+       rc = do_set_dqblk(dquot, di);
        dqput(dquot);
        mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
-       return 0;
+       return rc;
 }
 
 /* Generic routine for getting common part of quota file information */
index f3841f233069659e79a451a1d0f06f005f5ac83c..a6cf9269105c478e7a88db2ca6b074b8bcc0933d 100644 (file)
@@ -139,6 +139,9 @@ static int v1_read_file_info(struct super_block *sb, int type)
                goto out;
        }
        ret = 0;
+       /* limits are stored as unsigned 32-bit data */
+       dqopt->info[type].dqi_maxblimit = 0xffffffff;
+       dqopt->info[type].dqi_maxilimit = 0xffffffff;
        dqopt->info[type].dqi_igrace = dqblk.dqb_itime ? dqblk.dqb_itime : MAX_IQ_TIME;
        dqopt->info[type].dqi_bgrace = dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
 out:
index c519a583e681471c86687134c764262df138caf9..23b647f25d08a405bad3ba8917d550f120d60ccf 100644 (file)
@@ -59,6 +59,9 @@ static int v2_read_file_info(struct super_block *sb, int type)
                        sb->s_id);
                return -1;
        }
+       /* limits are stored as unsigned 32-bit data */
+       info->dqi_maxblimit = 0xffffffff;
+       info->dqi_maxilimit = 0xffffffff;
        info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
        info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
        info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
index eb560d031acd16de3209e175dddae4dc4de718e7..326cb80e386793706c22822cf4a773fb9371c0be 100644 (file)
@@ -206,6 +206,8 @@ struct mem_dqinfo {
        unsigned long dqi_flags;
        unsigned int dqi_bgrace;
        unsigned int dqi_igrace;
+       qsize_t dqi_maxblimit;
+       qsize_t dqi_maxilimit;
        union {
                struct v1_mem_dqinfo v1_i;
                struct v2_mem_dqinfo v2_i;