Commit ae17b2b3 authored by Chris Wright's avatar Chris Wright Committed by Linus Torvalds

[PATCH] RLIM: enforce rlimits for POSIX mqueue allocation

Add a user_struct to the mq_inode_info structure.  Charge the maximum number
of bytes that could be allocated to a mqueue to the user who creates the
mqueue.  This is checked against the per user rlimit.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent b1cae1ec
...@@ -67,6 +67,7 @@ struct mqueue_inode_info { ...@@ -67,6 +67,7 @@ struct mqueue_inode_info {
struct sigevent notify; struct sigevent notify;
pid_t notify_owner; pid_t notify_owner;
struct user_struct *user; /* user who created, for accouting */
struct sock *notify_sock; struct sock *notify_sock;
struct sk_buff *notify_cookie; struct sk_buff *notify_cookie;
...@@ -114,6 +115,9 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, ...@@ -114,6 +115,9 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
if (S_ISREG(mode)) { if (S_ISREG(mode)) {
struct mqueue_inode_info *info; struct mqueue_inode_info *info;
struct task_struct *p = current;
struct user_struct *u = p->user;
unsigned long mq_bytes, mq_msg_tblsz;
inode->i_fop = &mqueue_file_operations; inode->i_fop = &mqueue_file_operations;
inode->i_size = FILENT_SIZE; inode->i_size = FILENT_SIZE;
...@@ -123,8 +127,10 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, ...@@ -123,8 +127,10 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
init_waitqueue_head(&info->wait_q); init_waitqueue_head(&info->wait_q);
INIT_LIST_HEAD(&info->e_wait_q[0].list); INIT_LIST_HEAD(&info->e_wait_q[0].list);
INIT_LIST_HEAD(&info->e_wait_q[1].list); INIT_LIST_HEAD(&info->e_wait_q[1].list);
info->messages = NULL;
info->notify_owner = 0; info->notify_owner = 0;
info->qsize = 0; info->qsize = 0;
info->user = NULL; /* set when all is ok */
memset(&info->attr, 0, sizeof(info->attr)); memset(&info->attr, 0, sizeof(info->attr));
info->attr.mq_maxmsg = DFLT_MSGMAX; info->attr.mq_maxmsg = DFLT_MSGMAX;
info->attr.mq_msgsize = DFLT_MSGSIZEMAX; info->attr.mq_msgsize = DFLT_MSGSIZEMAX;
...@@ -132,12 +138,29 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, ...@@ -132,12 +138,29 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
info->attr.mq_maxmsg = attr->mq_maxmsg; info->attr.mq_maxmsg = attr->mq_maxmsg;
info->attr.mq_msgsize = attr->mq_msgsize; info->attr.mq_msgsize = attr->mq_msgsize;
} }
info->messages = kmalloc(info->attr.mq_maxmsg * sizeof(struct msg_msg *), GFP_KERNEL); mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
mq_bytes = (mq_msg_tblsz +
(info->attr.mq_maxmsg * info->attr.mq_msgsize));
spin_lock(&mq_lock);
if (u->mq_bytes + mq_bytes < u->mq_bytes ||
u->mq_bytes + mq_bytes >
p->rlim[RLIMIT_MSGQUEUE].rlim_cur) {
spin_unlock(&mq_lock);
goto out_inode;
}
u->mq_bytes += mq_bytes;
spin_unlock(&mq_lock);
info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
if (!info->messages) { if (!info->messages) {
make_bad_inode(inode); spin_lock(&mq_lock);
iput(inode); u->mq_bytes -= mq_bytes;
inode = NULL; spin_unlock(&mq_lock);
goto out_inode;
} }
/* all is ok */
info->user = get_uid(u);
} else if (S_ISDIR(mode)) { } else if (S_ISDIR(mode)) {
inode->i_nlink++; inode->i_nlink++;
/* Some things misbehave if size == 0 on a directory */ /* Some things misbehave if size == 0 on a directory */
...@@ -147,6 +170,10 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode, ...@@ -147,6 +170,10 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
} }
} }
return inode; return inode;
out_inode:
make_bad_inode(inode);
iput(inode);
return NULL;
} }
static int mqueue_fill_super(struct super_block *sb, void *data, int silent) static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
...@@ -205,6 +232,8 @@ static void mqueue_destroy_inode(struct inode *inode) ...@@ -205,6 +232,8 @@ static void mqueue_destroy_inode(struct inode *inode)
static void mqueue_delete_inode(struct inode *inode) static void mqueue_delete_inode(struct inode *inode)
{ {
struct mqueue_inode_info *info; struct mqueue_inode_info *info;
struct user_struct *user;
unsigned long mq_bytes;
int i; int i;
if (S_ISDIR(inode->i_mode)) { if (S_ISDIR(inode->i_mode)) {
...@@ -220,10 +249,15 @@ static void mqueue_delete_inode(struct inode *inode) ...@@ -220,10 +249,15 @@ static void mqueue_delete_inode(struct inode *inode)
clear_inode(inode); clear_inode(inode);
if (info->messages) { mq_bytes = (info->attr.mq_maxmsg * sizeof(struct msg_msg *) +
(info->attr.mq_maxmsg * info->attr.mq_msgsize));
user = info->user;
if (user) {
spin_lock(&mq_lock); spin_lock(&mq_lock);
user->mq_bytes -= mq_bytes;
queues_count--; queues_count--;
spin_unlock(&mq_lock); spin_unlock(&mq_lock);
free_uid(user);
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment