lkml.org 
[lkml]   [2011]   [Nov]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[RFC PATCH] tmpfs: support user quotas
    From
    Date
    From: Davidlohr Bueso <dave@gnu.org>

    This patch adds a new RLIMIT_TMPFSQUOTA resource limit to restrict an individual user's quota across all mounted tmpfs filesystems.
    It's well known that a user can easily fill up commonly used directories (like /tmp, /dev/shm) causing programs to break through DoS.

    By default the soft and hard limits are set the RLIM_INFINITY, thus maintaining the current functionality and allowing the user to populate
    the fs all he wants.

    This is one of the features requested in the Plumbers wishlist (http://0pointer.de/blog/projects/plumbers-wishlist-2.html).

    CC: Lennart Poettering <lennart@poettering.net>
    Signed-off-by: Davidlohr Bueso <dave@gnu.org>
    ---
    This is my first patch in these waters, so if I'm doing anything terrible wrong here please bare with me.

    fs/proc/base.c | 1 +
    include/asm-generic/resource.h | 4 +++-
    include/linux/sched.h | 3 +++
    mm/shmem.c | 14 ++++++++++++--
    4 files changed, 19 insertions(+), 3 deletions(-)

    diff --git a/fs/proc/base.c b/fs/proc/base.c
    index 2db1bd3..f839edb 100644
    --- a/fs/proc/base.c
    +++ b/fs/proc/base.c
    @@ -511,6 +511,7 @@ static const struct limit_names lnames[RLIM_NLIMITS] = {
    [RLIMIT_NICE] = {"Max nice priority", NULL},
    [RLIMIT_RTPRIO] = {"Max realtime priority", NULL},
    [RLIMIT_RTTIME] = {"Max realtime timeout", "us"},
    + [RLIMIT_TMPFSQUOTA] = {"Max tmpfs user quota", "bytes"},
    };

    /* Display limits for a process */
    diff --git a/include/asm-generic/resource.h b/include/asm-generic/resource.h
    index 61fa862..8ba77ad 100644
    --- a/include/asm-generic/resource.h
    +++ b/include/asm-generic/resource.h
    @@ -45,7 +45,8 @@
    0-39 for nice level 19 .. -20 */
    #define RLIMIT_RTPRIO 14 /* maximum realtime priority */
    #define RLIMIT_RTTIME 15 /* timeout for RT tasks in us */
    -#define RLIM_NLIMITS 16
    +#define RLIMIT_TMPFSQUOTA 16 /* maximum bytes for tmpfs quota */
    +#define RLIM_NLIMITS 17

    /*
    * SuS says limits have to be unsigned.
    @@ -87,6 +88,7 @@
    [RLIMIT_NICE] = { 0, 0 }, \
    [RLIMIT_RTPRIO] = { 0, 0 }, \
    [RLIMIT_RTTIME] = { RLIM_INFINITY, RLIM_INFINITY }, \
    + [RLIMIT_TMPFSQUOTA] = { RLIM_INFINITY, RLIM_INFINITY }, \
    }

    #endif /* __KERNEL__ */
    diff --git a/include/linux/sched.h b/include/linux/sched.h
    index e8acce7..849710f 100644
    --- a/include/linux/sched.h
    +++ b/include/linux/sched.h
    @@ -703,6 +703,9 @@ struct user_struct {
    /* protected by mq_lock */
    unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */
    #endif
    +#ifdef CONFIG_TMPFS
    + atomic_long_t shmem_bytes;
    +#endif
    unsigned long locked_shm; /* How many pages of mlocked shm ? */

    #ifdef CONFIG_KEYS
    diff --git a/mm/shmem.c b/mm/shmem.c
    index 45b9acb..1b8c638 100644
    --- a/mm/shmem.c
    +++ b/mm/shmem.c
    @@ -1159,7 +1159,12 @@ shmem_write_begin(struct file *file, struct address_space *mapping,
    struct page **pagep, void **fsdata)
    {
    struct inode *inode = mapping->host;
    + struct user_struct *user= current_user();
    pgoff_t index = pos >> PAGE_CACHE_SHIFT;
    +
    + if (atomic_long_read(&user->shmem_bytes) + len >
    + rlimit(RLIMIT_TMPFSQUOTA))
    + return -ENOSPC;
    return shmem_getpage(inode, index, pagep, SGP_WRITE, NULL);
    }

    @@ -1169,10 +1174,12 @@ shmem_write_end(struct file *file, struct address_space *mapping,
    struct page *page, void *fsdata)
    {
    struct inode *inode = mapping->host;
    + struct user_struct *user= current_user();

    - if (pos + copied > inode->i_size)
    + if (pos + copied > inode->i_size) {
    i_size_write(inode, pos + copied);
    -
    + atomic_long_add(copied, &user->shmem_bytes);
    + }
    set_page_dirty(page);
    unlock_page(page);
    page_cache_release(page);
    @@ -1535,12 +1542,15 @@ out:
    static int shmem_unlink(struct inode *dir, struct dentry *dentry)
    {
    struct inode *inode = dentry->d_inode;
    + struct user_struct *user = current_user();

    if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode))
    shmem_free_inode(inode->i_sb);

    dir->i_size -= BOGO_DIRENT_SIZE;
    inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
    + atomic_long_sub(inode->i_size, &user->shmem_bytes);
    +
    drop_nlink(inode);
    dput(dentry); /* Undo the count from "create" - this does all the work */
    return 0;
    --
    1.7.4.1




    \
     
     \ /
      Last update: 2011-11-06 22:19    [W:0.024 / U:32.284 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site