[PATCH 10/11] enforce rlimits for POSIX mqueue allocation

From: Chris Wright
Date: Tue May 11 2004 - 04:18:52 EST


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.

--- 2.6-rlimit/ipc/mqueue.c~mqueue_rlimit 2004-05-10 22:28:43.137833864 -0700
+++ 2.6-rlimit/ipc/mqueue.c 2004-05-10 22:30:44.530379392 -0700
@@ -67,6 +66,7 @@

struct sigevent notify;
pid_t notify_owner;
+ struct user_struct *user; /* user who created, for accouting */
struct sock *notify_sock;
struct sk_buff *notify_cookie;

@@ -114,6 +114,9 @@

if (S_ISREG(mode)) {
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_size = FILENT_SIZE;
@@ -123,8 +126,10 @@
init_waitqueue_head(&info->wait_q);
INIT_LIST_HEAD(&info->e_wait_q[0].list);
INIT_LIST_HEAD(&info->e_wait_q[1].list);
+ info->messages = NULL;
info->notify_owner = 0;
info->qsize = 0;
+ info->user = NULL; /* set when all is ok */
memset(&info->attr, 0, sizeof(info->attr));
info->attr.mq_maxmsg = DFLT_MSGMAX;
info->attr.mq_msgsize = DFLT_MSGSIZEMAX;
@@ -132,12 +137,29 @@
info->attr.mq_maxmsg = attr->mq_maxmsg;
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) {
- make_bad_inode(inode);
- iput(inode);
- inode = NULL;
+ spin_lock(&mq_lock);
+ u->mq_bytes -= mq_bytes;
+ spin_unlock(&mq_lock);
+ goto out_inode;
}
+ /* all is ok */
+ info->user = get_uid(u);
} else if (S_ISDIR(mode)) {
inode->i_nlink++;
/* Some things misbehave if size == 0 on a directory */
@@ -147,6 +169,10 @@
}
}
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)
@@ -205,6 +231,8 @@
static void mqueue_delete_inode(struct inode *inode)
{
struct mqueue_inode_info *info;
+ struct user_struct *user;
+ unsigned long mq_bytes;
int i;

if (S_ISDIR(inode->i_mode)) {
@@ -220,10 +248,15 @@

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);
+ user->mq_bytes -= mq_bytes;
queues_count--;
spin_unlock(&mq_lock);
+ free_uid(user);
}
}

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/