#115 Expired grace period gets overflowed when transporting over RPC


If disk usage reacheas soft limit, grace time starts counting down. Once the grace time expires, quota tools report "none" as the value, to signal the time has expired and soft limit is enforced now.

This works locally, but not over network. Here is listings for the same file system. First entry is a local mount, second entry is NFS mount:

# LANG=en_US ~petr/quota/linuxquota-git/quota -v
Disk quotas for user root (uid 0): 
     Filesystem  blocks   quota   limit   grace   files   quota   limit   grace
                     24*     20      40    none       3       0       0
                     24*     20      40 49710days       3       0       0

The "49710days" is wrong, it should display "none". Raw values (number of seconds) are:

# LANG=en_US ~petr/quota/linuxquota-git/quota -v --raw-grace
Disk quotas for user root (uid 0): 
     Filesystem  blocks   quota   limit   grace   files   quota   limit   grace
                     24*     20      40 1392886669       3       0       0       0
                     24*     20      40 5687853965       3       0       0       0

The bug is in rquota_server.c:servutil2netdqblk():

if (u->dqb_btime)
    n->rq_btimeleft = u->dqb_btime - now;
    n->rq_btimeleft = 0;
if (u->dqb_itime)
    n->rq_ftimeleft = u->dqb_itime - now;
    n->rq_ftimeleft = 0;

The u->dqb_btime stores the grace time as an absolute time. However the RPC transfers the value as a relative value (u->dqb_btime - now). If the grace time expires, u->dqb_btime will be less than now, so (u->dqb_btime - now) will be a negative value. However n->rq_btimeleft, as well as all struct rquota *n members, is unsigned int, so a wrapped value will get stored, and transmitted to the server. The server will see large positive value and it will interpret it as lots of days.

Just to be comprehensive, quota(1) tool interpret the absolute grace time value with this code:

void difftime2str(time_t seconds, char *buf)
    time_t now;

    buf[0] = 0;
    if (!seconds)
    if (seconds <= now) {
        strcpy(buf, _("none"));
    time2str(seconds - now, buf, TF_ROUND);

The question is how to fix it?

One could start interpret the RPC value as signed. This will fix the case when time expired. But it will break not-yet-expired times larger than 2^31 relative seconds. However I consider the broken case as very unlikely. So I incline to fix it this way.

The only problem is the struct rquota *n is generated code and uses unsigned int, which is usually 32-bits wide with GCC almost everywhere, but that's not guaranteed in general. One should probably to clamp the encoded value by the server to the signed int minimum and maximum to make sure the server and client will not disagree on the size.


  • Petr Písař

    Petr Písař - 2014-02-24

    This patch implements the idea.

    The second addressed issue is only hypothetical because I experience another overlflow on local ext4 file system when setting grace time to more that (2**31 - $(date +%s)), but that's another story.

  • Jan Kara

    Jan Kara - 2014-05-01

    Thanks for a throughout analysis. I was thinking whether we cannot fix this in a nicer way on the server but in the end I agree what you did is likely the simplest. If someone sees a problem with that, we can avoid overflowing the time left value on the server and define that 1 second grace time left actually means grace time has expired and fake values accordingly in util2net and net2util conversion functions. Sure it can happen that you really have 1 second left but practically there's no difference...

  • Jan Kara

    Jan Kara - 2014-05-01
    • status: open --> closed-fixed
    • Group: -->


Cancel  Add attachments

Get latest updates about Open Source Projects, Conferences and News.

Sign up for the SourceForge newsletter:

No, thanks