git: 98c467192082 - stable/12 - Escape any '.' characters in sysctl node names

Alan Somers asomers at FreeBSD.org
Sun Aug 22 23:03:28 UTC 2021


The branch stable/12 has been updated by asomers:

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

commit 98c467192082b3d4a6c91eeaa80868bb5231534c
Author:     Alan Somers <asomers at FreeBSD.org>
AuthorDate: 2021-07-21 21:11:00 +0000
Commit:     Alan Somers <asomers at FreeBSD.org>
CommitDate: 2021-08-22 22:43:50 +0000

    Escape any '.' characters in sysctl node names
    
    ZFS creates some sysctl nodes that include a pool name, and '.' is an
    allowed character in pool names.  But it's the separator in the sysctl
    tree, so it can't be included in a sysctl name.  Replace it with "%25".
    Handily, "%" is illegal in ZFS pool names, so there's no ambiguity
    there.
    
    PR:             257316
    Sponsored by:   Axcient
    Reviewed by:    freqlabs
    Differential Revision: https://reviews.freebsd.org/D31265
    
    (cherry picked from commit 6c9506559080da2914749bf611225d7c0a153609)
---
 sys/kern/kern_sysctl.c | 47 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 45 insertions(+), 2 deletions(-)

diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index fa0398896ad0..d40eec348ae3 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -109,6 +109,7 @@ static int sysctl_root(SYSCTL_HANDLER_ARGS);
 /* Root list */
 struct sysctl_oid_list sysctl__children = SLIST_HEAD_INITIALIZER(&sysctl__children);
 
+static char*	sysctl_escape_name(const char*);
 static int	sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del,
 		    int recurse);
 static int	sysctl_old_kernel(struct sysctl_req *, const void *, size_t);
@@ -734,6 +735,45 @@ sysctl_remove_name(struct sysctl_oid *parent, const char *name,
 	return (error);
 }
 
+/*
+ * Duplicate the provided string, escaping any illegal characters.  The result
+ * must be freed when no longer in use.
+ *
+ * The list of illegal characters is ".".
+ */
+static char*
+sysctl_escape_name(const char* orig)
+{
+	int i, s = 0, d = 0, nillegals = 0;
+	char *new;
+
+	/* First count the number of illegal characters */
+	for (i = 0; orig[i] != '\0'; i++) {
+		if (orig[i] == '.')
+			nillegals++;
+	}
+
+	/* Allocate storage for new string */
+	new = malloc(i + 2 * nillegals + 1, M_SYSCTLOID, M_WAITOK);
+
+	/* Copy the name, escaping characters as we go */
+	while (orig[s] != '\0') {
+		if (orig[s] == '.') {
+			/* %25 is the hexadecimal representation of '.' */
+			new[d++] = '%';
+			new[d++] = '2';
+			new[d++] = '5';
+			s++;
+		} else {
+			new[d++] = orig[s++];
+		}
+	}
+
+	/* Finally, nul-terminate */
+	new[d] = '\0';
+
+	return (new);
+}
 
 static int
 sysctl_remove_oid_locked(struct sysctl_oid *oidp, int del, int recurse)
@@ -816,14 +856,17 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
 	const char *label)
 {
 	struct sysctl_oid *oidp;
+	char *escaped;
 
 	/* You have to hook up somewhere.. */
 	if (parent == NULL)
 		return(NULL);
+	escaped = sysctl_escape_name(name);
 	/* Check if the node already exists, otherwise create it */
 	SYSCTL_WLOCK();
-	oidp = sysctl_find_oidname(name, parent);
+	oidp = sysctl_find_oidname(escaped, parent);
 	if (oidp != NULL) {
+		free(escaped, M_SYSCTLOID);
 		if ((oidp->oid_kind & CTLTYPE) == CTLTYPE_NODE) {
 			oidp->oid_refcnt++;
 			/* Update the context */
@@ -842,7 +885,7 @@ sysctl_add_oid(struct sysctl_ctx_list *clist, struct sysctl_oid_list *parent,
 	SLIST_INIT(&oidp->oid_children);
 	oidp->oid_number = number;
 	oidp->oid_refcnt = 1;
-	oidp->oid_name = strdup(name, M_SYSCTLOID);
+	oidp->oid_name = escaped;
 	oidp->oid_handler = handler;
 	oidp->oid_kind = CTLFLAG_DYN | kind;
 	oidp->oid_arg1 = arg1;


More information about the dev-commits-src-all mailing list