git: ddbfb544c6c9 - main - mqueuefs: Relax restriction that path must begin with a slash

From: Warner Losh <imp_at_FreeBSD.org>
Date: Thu, 23 May 2024 19:42:08 UTC
The branch main has been updated by imp:

URL: https://cgit.FreeBSD.org/src/commit/?id=ddbfb544c6c9726ae97bcaf105d11dec8b292877

commit ddbfb544c6c9726ae97bcaf105d11dec8b292877
Author:     Ricardo Branco <rbranco@suse.de>
AuthorDate: 2024-05-15 20:56:15 +0000
Commit:     Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-05-23 19:40:46 +0000

    mqueuefs: Relax restriction that path must begin with a slash
    
    This is needed to support Linux implementation which discards the leading slash when calling mq_open(2)
    
    Reviewed by: imp, kib
    Pull Request: https://github.com/freebsd/freebsd-src/pull/1248
---
 lib/libsys/mq_open.2   |  4 ++--
 sys/kern/uipc_mqueue.c | 34 ++++++++++++++++++++++------------
 2 files changed, 24 insertions(+), 14 deletions(-)

diff --git a/lib/libsys/mq_open.2 b/lib/libsys/mq_open.2
index 484fe95432da..4800ab18de59 100644
--- a/lib/libsys/mq_open.2
+++ b/lib/libsys/mq_open.2
@@ -35,7 +35,7 @@
 .\" the referee document.  The original Standard can be obtained online at
 .\"	http://www.opengroup.org/unix/online.html.
 .\"
-.Dd September 26, 2023
+.Dd May 15, 2024
 .Dt MQ_OPEN 2
 .Os
 .Sh NAME
@@ -322,7 +322,7 @@ Support for POSIX message queues first appeared in
 .Sh BUGS
 This implementation places strict requirements on the value of
 .Fa name :
-it must begin with a slash
+it may begin with a slash
 .Pq Ql /
 and contain no other slash characters.
 .Pp
diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c
index 2efdfc9dd04c..9276c918565f 100644
--- a/sys/kern/uipc_mqueue.c
+++ b/sys/kern/uipc_mqueue.c
@@ -2007,7 +2007,7 @@ static int
 kern_kmq_open(struct thread *td, const char *upath, int flags, mode_t mode,
     const struct mq_attr *attr)
 {
-	char path[MQFS_NAMELEN + 1];
+	char *path, pathbuf[MQFS_NAMELEN + 1];
 	struct mqfs_node *pn;
 	struct pwddesc *pdp;
 	struct file *fp;
@@ -2027,32 +2027,37 @@ kern_kmq_open(struct thread *td, const char *upath, int flags, mode_t mode,
 			return (EINVAL);
 	}
 
+	path = pathbuf;
 	error = copyinstr(upath, path, MQFS_NAMELEN + 1, NULL);
         if (error)
 		return (error);
 
 	/*
-	 * The first character of name must be a slash  (/) character
+	 * The first character of name may be a slash (/) character
 	 * and the remaining characters of name cannot include any slash
 	 * characters. 
 	 */
 	len = strlen(path);
-	if (len < 2 || path[0] != '/' || strchr(path + 1, '/') != NULL)
+	if (len < 2 || strchr(path + 1, '/') != NULL)
 		return (EINVAL);
+	if (path[0] == '/') {
+		path++;
+		len--;
+	}
 	/*
 	 * "." and ".." are magic directories, populated on the fly, and cannot
 	 * be opened as queues.
 	 */
-	if (strcmp(path, "/.") == 0 || strcmp(path, "/..") == 0)
+	if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0)
 		return (EINVAL);
-	AUDIT_ARG_UPATH1_CANON(path);
+	AUDIT_ARG_UPATH1_CANON(pathbuf);
 
 	error = falloc(td, &fp, &fd, O_CLOEXEC);
 	if (error)
 		return (error);
 
 	sx_xlock(&mqfs_data.mi_lock);
-	pn = mqfs_search(mqfs_data.mi_root, path + 1, len - 1, td->td_ucred);
+	pn = mqfs_search(mqfs_data.mi_root, path, len, td->td_ucred);
 	if (pn == NULL) {
 		if (!(flags & O_CREAT)) {
 			error = ENOENT;
@@ -2062,7 +2067,7 @@ kern_kmq_open(struct thread *td, const char *upath, int flags, mode_t mode,
 				error = ENFILE;
 			} else {
 				pn = mqfs_create_file(mqfs_data.mi_root,
-				         path + 1, len - 1, td->td_ucred,
+				         path, len, td->td_ucred,
 					 cmode);
 				if (pn == NULL) {
 					error = ENOSPC;
@@ -2134,23 +2139,28 @@ sys_kmq_open(struct thread *td, struct kmq_open_args *uap)
 int
 sys_kmq_unlink(struct thread *td, struct kmq_unlink_args *uap)
 {
-	char path[MQFS_NAMELEN+1];
+	char *path, pathbuf[MQFS_NAMELEN + 1];
 	struct mqfs_node *pn;
 	int error, len;
 
+	path = pathbuf;
 	error = copyinstr(uap->path, path, MQFS_NAMELEN + 1, NULL);
         if (error)
 		return (error);
 
 	len = strlen(path);
-	if (len < 2 || path[0] != '/' || strchr(path + 1, '/') != NULL)
+	if (len < 2 || strchr(path + 1, '/') != NULL)
 		return (EINVAL);
-	if (strcmp(path, "/.") == 0 || strcmp(path, "/..") == 0)
+	if (path[0] == '/') {
+		path++;
+		len--;
+	}
+	if (strcmp(path, ".") == 0 || strcmp(path, "..") == 0)
 		return (EINVAL);
-	AUDIT_ARG_UPATH1_CANON(path);
+	AUDIT_ARG_UPATH1_CANON(pathbuf);
 
 	sx_xlock(&mqfs_data.mi_lock);
-	pn = mqfs_search(mqfs_data.mi_root, path + 1, len - 1, td->td_ucred);
+	pn = mqfs_search(mqfs_data.mi_root, path, len, td->td_ucred);
 	if (pn != NULL)
 		error = do_unlink(pn, td->td_ucred);
 	else