linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
From: Davidlohr Bueso <dave@gnu.org>
To: Hugh Dickins <hughd@google.com>,
	Lennart Poettering <lennart@poettering.net>,
	Andrew Morton <akpm@linux-foundation.org>
Cc: lkml <linux-kernel@vger.kernel.org>, linux-mm@kvack.org
Subject: [RFC PATCH] tmpfs: support user quotas
Date: Sun, 06 Nov 2011 18:15:01 -0300	[thread overview]
Message-ID: <1320614101.3226.5.camel@offbook> (raw)

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



--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

             reply	other threads:[~2011-11-06 21:15 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-11-06 21:15 Davidlohr Bueso [this message]
2011-11-06 22:10 ` [RFC PATCH] tmpfs: support user quotas Lennart Poettering
2011-11-07  7:31 ` Christoph Hellwig
2011-11-07 11:29   ` Lennart Poettering
2011-11-07 14:20     ` Davidlohr Bueso
2011-11-07 13:58       ` Alan Cox
2011-11-07 14:27         ` Kay Sievers
2011-11-07 22:53           ` Alan Cox
2011-11-07 22:57             ` Glauber Costa
2011-11-07 23:07             ` Lennart Poettering
2011-11-07 23:43               ` Alan Cox
2011-11-08  0:25                 ` Lennart Poettering
2011-11-08  0:46                   ` Alan Cox
2011-11-07 14:30         ` Lennart Poettering
2011-11-07 22:15           ` KOSAKI Motohiro
2011-11-07 22:37             ` Kay Sievers
2011-11-08  0:33               ` KOSAKI Motohiro
2011-11-07 23:01           ` Alan Cox
2011-11-07  9:11 ` Valdis.Kletnieks
2011-11-07 14:49   ` Davidlohr Bueso

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1320614101.3226.5.camel@offbook \
    --to=dave@gnu.org \
    --cc=akpm@linux-foundation.org \
    --cc=hughd@google.com \
    --cc=lennart@poettering.net \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).