Module Name:    src
Committed By:   rmind
Date:           Tue May 26 00:39:14 UTC 2009

Modified Files:
        src/sys/kern: sys_mqueue.c

Log Message:
- Slightly rework the way permissions are checked. Neither mq_receive() not
  mq_send() should fail due to permissions.  Noted by Stathis Kamperis!
- Check for empty message queue name (POSIX does not allow this for regular
  files, and it's weird), check for DTYPE_MQUEUE, fix permission check in
  mq_unlink(), clean up.


To generate a diff of this commit:
cvs rdiff -u -r1.17 -r1.18 src/sys/kern/sys_mqueue.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/sys_mqueue.c
diff -u src/sys/kern/sys_mqueue.c:1.17 src/sys/kern/sys_mqueue.c:1.18
--- src/sys/kern/sys_mqueue.c:1.17	Sat May 16 23:58:09 2009
+++ src/sys/kern/sys_mqueue.c	Tue May 26 00:39:14 2009
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_mqueue.c,v 1.17 2009/05/16 23:58:09 rmind Exp $	*/
+/*	$NetBSD: sys_mqueue.c,v 1.18 2009/05/26 00:39:14 rmind Exp $	*/
 
 /*
  * Copyright (c) 2007, 2008 Mindaugas Rasiukevicius <rmind at NetBSD org>
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.17 2009/05/16 23:58:09 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_mqueue.c,v 1.18 2009/05/26 00:39:14 rmind Exp $");
 
 #include <sys/param.h>
 #include <sys/types.h>
@@ -87,8 +87,6 @@
 static int	mq_stat_fop(file_t *, struct stat *);
 static int	mq_close_fop(file_t *);
 
-#define	FNOVAL	-1
-
 static const struct fileops mqops = {
 	.fo_read = fbadop_read,
 	.fo_write = fbadop_write,
@@ -167,57 +165,28 @@
 }
 
 /*
- * Check access against message queue.
- */
-static inline int
-mqueue_access(struct lwp *l, struct mqueue *mq, int access)
-{
-	mode_t acc_mode = 0;
-
-	KASSERT(mutex_owned(&mq->mq_mtx));
-	KASSERT(access != FNOVAL);
-
-	/* Note the difference between VREAD/VWRITE and FREAD/FWRITE */
-	if (access & FREAD)
-		acc_mode |= VREAD;
-	if (access & FWRITE)
-		acc_mode |= VWRITE;
-
-	return vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid,
-	    acc_mode, l->l_cred);
-}
-
-/*
- * Get the mqueue from the descriptor.
- *  => locks the message queue, if found
- *  => increments the reference on file entry
+ * mqueue_get: get the mqueue from the descriptor.
+ *  => locks the message queue, if found.
+ *  => holds a reference on the file descriptor.
  */
 static int
-mqueue_get(struct lwp *l, mqd_t mqd, int access, file_t **fpr)
+mqueue_get(mqd_t mqd, file_t **fpr)
 {
-	file_t *fp;
 	struct mqueue *mq;
+	file_t *fp;
 
-	/* Get the file and descriptor */
 	fp = fd_getfile((int)mqd);
-	if (fp == NULL)
+	if (__predict_false(fp == NULL)) {
 		return EBADF;
-
-	/* Increment the reference of file entry, and lock the mqueue */
-	mq = fp->f_data;
-	*fpr = fp;
-	mutex_enter(&mq->mq_mtx);
-	if (access == FNOVAL) {
-		KASSERT(mutex_owned(&mq->mq_mtx));
-		return 0;
 	}
-
-	/* Check the access mode and permission */
-	if ((fp->f_flag & access) != access || mqueue_access(l, mq, access)) {
-		mutex_exit(&mq->mq_mtx);
+	if (__predict_false(fp->f_type != DTYPE_MQUEUE)) {
 		fd_putfile((int)mqd);
-		return EPERM;
+		return EBADF;
 	}
+	mq = fp->f_data;
+	mutex_enter(&mq->mq_mtx);
+
+	*fpr = fp;
 	return 0;
 }
 
@@ -364,6 +333,12 @@
 			return EMFILE;
 		}
 
+		/* Empty name is invalid */
+		if (name[0] == '\0') {
+			kmem_free(name, MQ_NAMELEN);
+			return EINVAL;
+		}
+	
 		/* Check for mqueue attributes */
 		if (SCARG(uap, attr)) {
 			error = copyin(SCARG(uap, attr), &attr,
@@ -400,7 +375,9 @@
 
 		strlcpy(mq_new->mq_name, name, MQ_NAMELEN);
 		memcpy(&mq_new->mq_attrib, &attr, sizeof(struct mq_attr));
-		mq_new->mq_attrib.mq_flags = oflag;
+
+		CTASSERT((O_MASK & (MQ_UNLINK | MQ_RECEIVE)) == 0);
+		mq_new->mq_attrib.mq_flags = (O_MASK & oflag);
 
 		/* Store mode and effective UID with GID */
 		mq_new->mq_mode = ((SCARG(uap, mode) &
@@ -425,6 +402,8 @@
 	mutex_enter(&mqlist_mtx);
 	mq = mqueue_lookup(name);
 	if (mq) {
+		mode_t acc_mode;
+
 		KASSERT(mutex_owned(&mq->mq_mtx));
 
 		/* Check if mqueue is not marked as unlinking */
@@ -437,8 +416,20 @@
 			error = EEXIST;
 			goto exit;
 		}
-		/* Check the permission */
-		if (mqueue_access(l, mq, fp->f_flag)) {
+
+		/*
+		 * Check the permissions.  Note the difference between
+		 * VREAD/VWRITE and FREAD/FWRITE.
+		 */
+		acc_mode = 0;
+		if (fp->f_flag & FREAD) {
+			acc_mode |= VREAD;
+		}
+		if (fp->f_flag & FWRITE) {
+			acc_mode |= VWRITE;
+		}
+		if (vaccess(VNON, mq->mq_mode, mq->mq_euid, mq->mq_egid,
+		    acc_mode, l->l_cred)) {
 			error = EACCES;
 			goto exit;
 		}
@@ -509,7 +500,7 @@
 	int error;
 
 	/* Get the message queue */
-	error = mqueue_get(l, mqdes, FREAD, &fp);
+	error = mqueue_get(mqdes, &fp);
 	if (error)
 		return error;
 	mq = fp->f_data;
@@ -670,7 +661,7 @@
 	msg->msg_prio = msg_prio;
 
 	/* Get the mqueue */
-	error = mqueue_get(l, mqdes, FWRITE, &fp);
+	error = mqueue_get(mqdes, &fp);
 	if (error) {
 		mqueue_freemsg(msg, size);
 		return error;
@@ -814,7 +805,7 @@
 			return error;
 	}
 
-	error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp);
+	error = mqueue_get(SCARG(uap, mqdes), &fp);
 	if (error)
 		return error;
 	mq = fp->f_data;
@@ -853,7 +844,7 @@
 	int error;
 
 	/* Get the message queue */
-	error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp);
+	error = mqueue_get(SCARG(uap, mqdes), &fp);
 	if (error)
 		return error;
 	mq = fp->f_data;
@@ -884,7 +875,7 @@
 	nonblock = (attr.mq_flags & O_NONBLOCK);
 
 	/* Get the message queue */
-	error = mqueue_get(l, SCARG(uap, mqdes), FNOVAL, &fp);
+	error = mqueue_get(SCARG(uap, mqdes), &fp);
 	if (error)
 		return error;
 	mq = fp->f_data;
@@ -942,7 +933,8 @@
 	}
 
 	/* Check the permissions */
-	if (mqueue_access(l, mq, FWRITE)) {
+	if (kauth_cred_geteuid(l->l_cred) != mq->mq_euid &&
+	    kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) {
 		mutex_exit(&mq->mq_mtx);
 		error = EACCES;
 		goto error;

Reply via email to