Skip to contentSkip to conversation

tmpfs: support user quotas

RFC PATCH In review Davidlohr Bueso 8 participants 20 messages Nov 6, 2011 – Nov 8, 2011

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

RFC PATCH 1/1 tmpfs: support user quotas

From: Davidlohr Bueso <[email protected]>

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 <[email protected]>

---
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(-)
fs/proc/base.c +1 -0
index 2db1bd3..f839edb 100644
@@ -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 */
include/asm-generic/resource.h +3 -1
index 61fa862..8ba77ad 100644
@@ -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__ */
include/linux/sched.h +3 -0
index e8acce7..849710f 100644
@@ -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
mm/shmem.c +12 -2
index 45b9acb..1b8c638 100644
@@ -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;
Signature · 10 lines
1.7.4.1



--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  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:"[email protected]"> [email protected] </a>
#1 lore raw
Quoted 4 lines · Davidlohr Bueso

From: Davidlohr Bueso <[email protected]>

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.

Thanks a lot for this work! One comment without looking at the patch in detail:

mm/shmem.c shmem_write_begin(struct file *file, struct address_space *mapping, · line 1167

Quoted 3 lines
mm/shmem.c +3 -0
+	if (atomic_long_read(&user->shmem_bytes) + len > 
+	    rlimit(RLIMIT_TMPFSQUOTA))
+		return -ENOSPC;

This should be EDQUOT "Disk quota exceeded", not ENOSPC "No space left on device".

Lennart

Signature · 8 lines
Lennart Poettering - Red Hat, Inc.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  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:"[email protected]"> [email protected] </a>
#2 lore raw
In reply to Davidlohr Bueso
Quoted 4 lines · Davidlohr Bueso

From: Davidlohr Bueso <[email protected]>

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.

Please jyst implement the normal user/group quota interfaces we use for other filesystem.

#3 lore raw
Quoted 9 lines · Christoph Hellwig
Quoted 4 lines · Davidlohr Bueso

From: Davidlohr Bueso <[email protected]>

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.

Please jyst implement the normal user/group quota interfaces we use for other filesystem.

Please don't.

tmpfs by its very nature is volatile, which means that we'd have to upload the quota data explicitly each time we mount a tmpfs, which means we'd have to add quite some userspace infrastructure to make tmpfs work with quota. Either every time a tmpfs is mounted we'd have to apply a quota for every configured user and every future user to it (which is simply not realistic) or on every user logging in we'd have to go through all tmpfs mount points and apply a user-specific quota setting to it -- which isn't much less ugly and complex. Just using a user-specific RLIMIT is much much simpler and beautiful there, and requires almost no changes to userspace.

On top of that I think a global quota over all tmpfs is actually preferable than a per-tmpfs quota, because what you want to enforce is that clients cannot drain the pool that tmpfs is backed from but how they distribute their share of that pool on the various tmpfs mounted doesn't really matter in order to avoid DoS vulnerabilities.

In short: a resource limit for tmpfs quota looks like the best solution here, which does exactly what userspace wants.

Lennart

--
Lennart Poettering - Red Hat, Inc.

#4 lore raw
Quoted 25 lines · Lennart Poettering
Quoted 9 lines · Christoph Hellwig
Quoted 4 lines · Davidlohr Bueso

From: Davidlohr Bueso <[email protected]>

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.

Please jyst implement the normal user/group quota interfaces we use for other filesystem.

Please don't.

tmpfs by its very nature is volatile, which means that we'd have to upload the quota data explicitly each time we mount a tmpfs, which means we'd have to add quite some userspace infrastructure to make tmpfs work with quota. Either every time a tmpfs is mounted we'd have to apply a quota for every configured user and every future user to it (which is simply not realistic) or on every user logging in we'd have to go through all tmpfs mount points and apply a user-specific quota setting to it -- which isn't much less ugly and complex. Just using a user-specific RLIMIT is much much simpler and beautiful there, and requires almost no changes to userspace.

Quoted 5 lines

On top of that I think a global quota over all tmpfs is actually preferable than a per-tmpfs quota, because what you want to enforce is that clients cannot drain the pool that tmpfs is backed from but how they distribute their share of that pool on the various tmpfs mounted doesn't really matter in order to avoid DoS vulnerabilities.

Right, rlimit approach guarantees a simple way of dealing with users across all tmpfs instances.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>

#5 lore raw
Quoted 2 lines

Right, rlimit approach guarantees a simple way of dealing with users across all tmpfs instances.

Which is almost certainly not what you want to happen. Think about direct rendering.

For simple stuff tmpfs already supports size/nr_blocks/nr_inodes mount options so you can mount private resource constrained tmpfs objects already without kernel changes. No rlimit hacks needed - and rlimit is the wrong API anyway.

Alan

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>

#6 lore raw
Quoted 10 lines · Alan Cox
Quoted 2 lines

Right, rlimit approach guarantees a simple way of dealing with users across all tmpfs instances.

Which is almost certainly not what you want to happen. Think about direct rendering.

For simple stuff tmpfs already supports size/nr_blocks/nr_inodes mount options so you can mount private resource constrained tmpfs objects already without kernel changes. No rlimit hacks needed - and rlimit is the wrong API anyway.

What part of the message did you read? This is about _per_user_ limits, not global limits!

Any untrusted user can fill /dev/shm today and DOS many services that way on any machine out there. Same for /tmp when it's a tmpfs, or /run/user. This is an absolutely unacceptable state and needs fixing.

I don't care about which interface it is, if someting else fits better, let's discuss that, but it has surely absolutely noting to do with size/nr_blocks/nr_inodes.

Kay

#7 lore raw
Quoted 2 lines

What part of the message did you read? This is about _per_user_ limits, not global limits!

What part of 'we support lots of mounts' don't you understand. Or perhaps you could go use a control group for it ?

Quoted 3 lines

Any untrusted user can fill /dev/shm today and DOS many services that way on any machine out there. Same for /tmp when it's a tmpfs, or /run/user. This is an absolutely unacceptable state and needs fixing.

Actually if you've mounted it with limits they can be a nuisance but little more, and if you are running with memory overcommit disabled then its accounted for in that. If you are running with memory over commit allowed (as eg Red Hat and Fedora do) you are peeing into the wind at this point anyway so wasting time.

Quoted 3 lines

I don't care about which interface it is, if someting else fits better, let's discuss that, but it has surely absolutely noting to do with size/nr_blocks/nr_inodes.

Per user would be quota, per process would be rlimit. Quite simple really, nice standard interfaces we've had for years. Various systems have been quotaing /tmp/ for a long time. Smart secure ones of course mount a per user /tmp via PAM or similar to avoid /tmp attacks and in that case the mount options I pointed out already do the job.

Quota isn't entirely trivial because you want your quota db initialised at mount so you'd need to pass a quota file pointer to the mount command ideally. All doable however and makes the management easy and means you get all the application expected behaviour when you exceed your limits (that is for properly written stuff - lots of crappy badly written desktop programs randomly crash or worse as we already know)

This is why I'm confused - you are wittering about all sorts of security stuff but you are not addressing the more serious matters first - the ones that go beyond a DoS.

Alan

#8 lore raw
Quoted 5 lines · Alan Cox
Quoted 2 lines

What part of the message did you read? This is about _per_user_ limits, not global limits!

What part of 'we support lots of mounts' don't you understand. Or perhaps you could go use a control group for it ?

We are trying to implement an indirect limit on slab objects in the memory controller.
Our specific use case is to control the number of dentries currently pinned in some given physical filesystem. If you can't allocate a dentry from the dentry cache, you can also not DoS a system - in our case, a container.

Maybe this will also solve your problems?

Quoted 31 lines
Quoted 3 lines

Any untrusted user can fill /dev/shm today and DOS many services that way on any machine out there. Same for /tmp when it's a tmpfs, or /run/user. This is an absolutely unacceptable state and needs fixing.

Actually if you've mounted it with limits they can be a nuisance but little more, and if you are running with memory overcommit disabled then its accounted for in that. If you are running with memory over commit allowed (as eg Red Hat and Fedora do) you are peeing into the wind at this point anyway so wasting time.

Quoted 3 lines

I don't care about which interface it is, if someting else fits better, let's discuss that, but it has surely absolutely noting to do with size/nr_blocks/nr_inodes.

Per user would be quota, per process would be rlimit. Quite simple really, nice standard interfaces we've had for years. Various systems have been quotaing /tmp/ for a long time. Smart secure ones of course mount a per user /tmp via PAM or similar to avoid /tmp attacks and in that case the mount options I pointed out already do the job.

Quota isn't entirely trivial because you want your quota db initialised at mount so you'd need to pass a quota file pointer to the mount command ideally. All doable however and makes the management easy and means you get all the application expected behaviour when you exceed your limits (that is for properly written stuff - lots of crappy badly written desktop programs randomly crash or worse as we already know)

This is why I'm confused - you are wittering about all sorts of security stuff but you are not addressing the more serious matters first - the ones that go beyond a DoS.

Quoted 8 lines

Alan

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected]</a>

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>

#9 lore raw
In reply to Alan Cox
Quoted 2 lines · Alan Cox

Per user would be quota, per process would be rlimit. Quite simple really, nice standard interfaces we've had for years. Various systems

Uh, have you ever really looked at resource limits? Some of them are per-user, not per-process, i.e. RLIMIT_NPROC. And this would just be another one.

Lennart

Signature · 8 lines
Lennart Poettering - Red Hat, Inc.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  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:"[email protected]"> [email protected] </a>
#10 lore raw
Quoted 8 lines · On Tue, 8 Nov 2011 00:07:12 +0100 Lennart Poettering <[email protected]>…
Quoted 2 lines · Alan Cox

Per user would be quota, per process would be rlimit. Quite simple really, nice standard interfaces we've had for years. Various systems

Uh, have you ever really looked at resource limits? Some of them are per-user, not per-process, i.e. RLIMIT_NPROC. And this would just be another one.

NPROC is a bit of an oddity.

And the standards have no idea how a resource limit hit for an fs would be reported, nor how an app installer would check for it. Quota on the other hand is defined behaviour.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>

#11 lore raw
Quoted 6 lines · Alan Cox
Quoted 2 lines · On Tue, 8 Nov 2011 00:07:12 +0100 Lennart Poettering <[email protected]>…

On Mon, 07.11.11 22:53, Alan Cox ([email protected]) wrote:

Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

Per user would be quota, per process would be rlimit. Quite simple really, nice standard interfaces we've had for years. Various systems

Uh, have you ever really looked at resource limits? Some of them are per-user, not per-process, i.e. RLIMIT_NPROC. And this would just be another one.

NPROC is a bit of an oddity.

And half of the other resource limits are "oddities" too? For example RLIMIT_SIGPENDING is per-user and so is RLIMIT_MSGQUEUE, and others too.

Quoted 3 lines

And the standards have no idea how a resource limit hit for an fs would be reported, nor how an app installer would check for it. Quota on the other hand is defined behaviour.

EDQUOT is POSIX, but afaik there is no POSIX standardized API for quota, is there? i.e. the reporting of the user hitting quota is defined, but how to set the quota is left open. Which is nice, since it gives us the flexibility to use resource limits here, since they so nicely apply to the problem.

Lennart

Signature · 1 line
Lennart Poettering - Red Hat, Inc.
#12 lore raw
Quoted 3 lines

And half of the other resource limits are "oddities" too? For example RLIMIT_SIGPENDING is per-user and so is RLIMIT_MSGQUEUE, and others too.

When you look at the standards - yes.

Quoted 6 lines
Quoted 3 lines

And the standards have no idea how a resource limit hit for an fs would be reported, nor how an app installer would check for it. Quota on the other hand is defined behaviour.

EDQUOT is POSIX, but afaik there is no POSIX standardized API for quota, is there? i.e. the reporting of the user hitting quota is defined, but

Its part of Unix and its well defined and used by applications, both for hitting quota (the easy bit), checking quota (when checking space for things particularly), and manipulating them

The latter bit is nice, it means you can mount with a user quota set in the mount options, and if you want then use quota tools to change the quota of a specific user or two that have special rules.

Alan

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>

#13 lore raw
In reply to Alan Cox
Quoted 6 lines · Alan Cox
Quoted 3 lines

Right, rlimit approach guarantees a simple way of dealing with users across all tmpfs instances.

Which is almost certainly not what you want to happen. Think about direct rendering.

I don't see what direct rendering has to do with closing the security hole that /dev/shm currently is.

Quoted 4 lines

For simple stuff tmpfs already supports size/nr_blocks/nr_inodes mount options so you can mount private resource constrained tmpfs objects already without kernel changes. No rlimit hacks needed - and rlimit is the wrong API anyway.

Uh? I am pretty sure we don't want to mount a private tmpfs for each user in /dev/shm and /tmp. If you have 500 users you'd have 500 tmpfs on /tmp and on /dev/shm. Despite that without some ugly namespace hackery you couldn't make them all appear in /tmp as /dev/shm without subdirectories. Don't forget that /dev/shm and /tmp are an established userspace API.

Resource limits are exactly the API that makes sense here, because:

a) we only want one tmpfs on /tmp, and one tmpfs on /dev/shm, not 500 on each for each user

b) we cannot move /dev/shm, /tmp around without breaking userspace massively

c) we want a global limit across all tmpfs file systems for each user

d) we don't want to have to upload the quota database into each tmpfs at mount time.

And hence: a per user RLIMIT is exactly the minimal solution we want here.

Lennart

Signature · 8 lines
Lennart Poettering - Red Hat, Inc.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  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:"[email protected]"> [email protected] </a>
#14 lore raw
Quoted 24 lines · Lennart Poettering
Quoted 6 lines · Alan Cox
Quoted 3 lines

Right, rlimit approach guarantees a simple way of dealing with users across all tmpfs instances.

Which is almost certainly not what you want to happen. Think about direct rendering.

I don't see what direct rendering has to do with closing the security hole that /dev/shm currently is.

Quoted 4 lines

For simple stuff tmpfs already supports size/nr_blocks/nr_inodes mount options so you can mount private resource constrained tmpfs objects already without kernel changes. No rlimit hacks needed - and rlimit is the wrong API anyway.

Uh? I am pretty sure we don't want to mount a private tmpfs for each user in /dev/shm and /tmp. If you have 500 users you'd have 500 tmpfs on /tmp and on /dev/shm. Despite that without some ugly namespace hackery you couldn't make them all appear in /tmp as /dev/shm without subdirectories. Don't forget that /dev/shm and /tmp are an established userspace API.

Quoted 4 lines

Resource limits are exactly the API that makes sense here, because:

a) we only want one tmpfs on /tmp, and one tmpfs on /dev/shm, not 500 on each for each user

Ok, seems fair.

Quoted 2 lines

b) we cannot move /dev/shm, /tmp around without breaking userspace massively

agreed.

Quoted 2 lines

c) we want a global limit across all tmpfs file systems for each user

Why? Is there any benefit this?

Quoted 5 lines

d) we don't want to have to upload the quota database into each tmpfs at mount time.

And hence: a per user RLIMIT is exactly the minimal solution we want here.

If you want per-user limitation, RLIMIT is bad idea. RLIMIT is only inherited by fork. So, The api semantics clearly mismatch your usecase.

Instead, I suggest to implement new sysfs knob.

Thank you.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>

#15 lore raw
Quoted 4 lines · KOSAKI Motohiro

(11/7/2011 6:30 AM), Lennart Poettering wrote:

If you want per-user limitation, RLIMIT is bad idea. RLIMIT is only inherited by fork. So, The api semantics clearly mismatch your usecase.

Like RLIMIT_NPROC?

Quoted 1 line

Instead, I suggest to implement new sysfs knob.

Where would users show up in sysfs?

Kay

#16 lore raw
Quoted 8 lines · Kay Sievers
Quoted 4 lines · KOSAKI Motohiro

(11/7/2011 6:30 AM), Lennart Poettering wrote:

If you want per-user limitation, RLIMIT is bad idea. RLIMIT is only inherited by fork. So, The api semantics clearly mismatch your usecase.

Like RLIMIT_NPROC?

I suggest to don't follow useless interfaces.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>

#17 lore raw
In reply to Lennart Poettering
Quoted 5 lines
Quoted 2 lines

Which is almost certainly not what you want to happen. Think about direct rendering.

I don't see what direct rendering has to do with closing the security hole that /dev/shm currently is.

Direct render objects (like shared memory objects) are backed by shmfs, so if you impose random limits on the shmfs you'll get weird graphics happenings. You use a *lot* of shmfs objects when you are running 3D gaming, enormous amounts for all your textures and the like.

The DRM case means you can't set tight limits on shmfs and expect to play Warcraft.

Quoted 2 lines

Uh? I am pretty sure we don't want to mount a private tmpfs for each user in /dev/shm and /tmp. If you have 500 users you'd have 500 tmpfs on

Oh I do. That would actually do something abut temporary file handling which is a much much bigger issue than a DoS when people get it wrong. It's a bit of Unix history that wants sorting out more than /usr and /bin...

Quoted 1 line

/tmp and on /dev/shm. Despite that without some ugly namespace hackery

Only if they were all logged in

Quoted 3 lines

you couldn't make them all appear in /tmp as /dev/shm without subdirectories. Don't forget that /dev/shm and /tmp are an established userspace API.

Don't forget there have been pam modules for doing per user /tmp/ for years and years.

Quoted 1 line

Resource limits are exactly the API that makes sense here, because:

No because they are inherited process things and the exhaustion behaviour is not standards defined. Christoph is right that this should be implemnted via quota.

It might well be that your quota implementation is handled by a mount option (sysfs just makes it more complex) and that

mount blah -oquotaallusers=16G

is how you set it up, but doing it via quota interfaces makes all sorts of crap just work including warning users about quota limits.

Alan

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>

#18 lore raw
In reply to Davidlohr Bueso

mm/shmem.c shmem_write_begin(struct file *file, struct address_space *mapping, · line 1163

Quoted 6 lines · Davidlohr Bueso
mm/shmem.c +3 -0
@@ -1159,7 +1159,12 @@ shmem_write_begin(struct file *file, struct address_space *mapping,
 			struct page **pagep, void **fsdata)
 
+	if (atomic_long_read(&user->shmem_bytes) + len > 
+	    rlimit(RLIMIT_TMPFSQUOTA))
+		return -ENOSPC;

Is this a per-process or per-user limit? If it's per-process, it doesn't really do much good, because a user can use multiple processes to over-run the limit (either intentionally or accidentally).

mm/shmem.c shmem_write_end(struct file *file, struct address_space *mapping, · line 1179

Quoted 7 lines
mm/shmem.c +3 -0
@@ -1169,10 +1174,12 @@ shmem_write_end(struct file *file, struct address_space *mapping,
 			struct page *page, void *fsdata)
 
+	if (pos + copied > inode->i_size) {
 		i_size_write(inode, pos + copied);
+		atomic_long_add(copied, &user->shmem_bytes);
+	}

If this is per-user, it's racy with shmem_write_begin() - two processes can hit the write_begin(), be under quota by (say) 1M, but by the time they both complete the user is 1M over the quota.

mm/shmem.c out: · line 1552

Quoted 3 lines
mm/shmem.c +2 -0
 @@ -1535,12 +1542,15 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry)
+	struct user_struct *user = current_user();
+	atomic_long_sub(inode->i_size, &user->shmem_bytes);

What happens here if user 'fred' creates a file on a tmpfs, and then logs out so he has no processes running, and then root does a 'find tmpfs -user fred -exec rm {} \;' to clean up? We just decremented root's quota, not fred's....

#19 lore raw
Quoted 5 lines · On Mon, 2011-11-07 at 04:11 -0500, [email protected] wrote:
Quoted 2 lines · Davidlohr Bueso
mm/shmem.c +0 -0
@@ -1159,7 +1159,12 @@ shmem_write_begin(struct file *file, struct address_space *mapping,
 			struct page **pagep, void **fsdata)
Quoted 7 lines

mm/shmem.c shmem_write_begin(struct file *file, struct address_space *mapping, · line 1167

Quoted 3 lines
mm/shmem.c +3 -0
+	if (atomic_long_read(&user->shmem_bytes) + len > 
+	    rlimit(RLIMIT_TMPFSQUOTA))
+		return -ENOSPC;

Is this a per-process or per-user limit? If it's per-process, it doesn't really do much good, because a user can use multiple processes to over-run the limit (either intentionally or accidentally).

This is a per-user limit.

Quoted 4 lines
Quoted 3 lines
mm/shmem.c +0 -0
@@ -1169,10 +1174,12 @@ shmem_write_end(struct file *file, struct address_space *mapping,
 			struct page *page, void *fsdata)
Quoted 8 lines

mm/shmem.c shmem_write_end(struct file *file, struct address_space *mapping, · line 1182

Quoted 4 lines
mm/shmem.c +3 -0
+	if (pos + copied > inode->i_size) {
 		i_size_write(inode, pos + copied);
+		atomic_long_add(copied, &user->shmem_bytes);
+	}

If this is per-user, it's racy with shmem_write_begin() - two processes can hit the write_begin(), be under quota by (say) 1M, but by the time they both complete the user is 1M over the quota.

I guess using a spinlock instead of atomic operations would serve the purpose.

Quoted 8 lines

mm/shmem.c out: · line 1552

Quoted 3 lines
mm/shmem.c +2 -0
 @@ -1535,12 +1542,15 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry)
+	struct user_struct *user = current_user();
+	atomic_long_sub(inode->i_size, &user->shmem_bytes);

What happens here if user 'fred' creates a file on a tmpfs, and then logs out so he has no processes running, and then root does a 'find tmpfs -user fred -exec rm {} \;' to clean up? We just decremented root's quota, not fred's....

Would the same would occur with mqueues? I haven't tested it but I don't see anywhere that user->mq_bytes is decreased like this.

Thanks,
Davidlohr

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected]. 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:"[email protected]"> [email protected] </a>