Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 7 Oct 2010 18:00:55 +0000 (UTC)
From:      Jaakko Heinonen <jh@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r213526 - in head: share/man/man9 sys/kern sys/sys
Message-ID:  <201010071800.o97I0tiW048627@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jh
Date: Thu Oct  7 18:00:55 2010
New Revision: 213526
URL: http://svn.freebsd.org/changeset/base/213526

Log:
  Check the device name validity on device registration.
  
  A new function prep_devname() sanitizes a device name by removing
  leading and redundant sequential slashes. The function returns an error
  for names which already exist or are considered invalid.
  
  A new flag MAKEDEV_CHECKNAME for make_dev_p(9) and make_dev_credf(9)
  indicates that the caller is prepared to handle an error related to the
  device name. An invalid name triggers a panic if the flag is not
  specified.
  
  Document the MAKEDEV_CHECKNAME flag in the make_dev(9) manual page.
  
  Idea from:	kib
  Reviewed by:	kib

Modified:
  head/share/man/man9/make_dev.9
  head/sys/kern/kern_conf.c
  head/sys/sys/conf.h

Modified: head/share/man/man9/make_dev.9
==============================================================================
--- head/share/man/man9/make_dev.9	Thu Oct  7 17:49:19 2010	(r213525)
+++ head/share/man/man9/make_dev.9	Thu Oct  7 18:00:55 2010	(r213526)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd September 5, 2010
+.Dd October 7, 2010
 .Dt MAKE_DEV 9
 .Os
 .Sh NAME
@@ -131,12 +131,18 @@ argument alters the operation of
 .Fn make_dev_credf .
 The following values are currently accepted:
 .Pp
-.Bd -literal -offset indent -compact
-MAKEDEV_REF	reference the created device
-MAKEDEV_NOWAIT	do not sleep, may return NULL
-MAKEDEV_WAITOK	allow the function to sleep to satisfy malloc
-MAKEDEV_ETERNAL	created device will be never destroyed
-.Ed
+.Bl -tag -width "MAKEDEV_CHECKNAME" -compact -offset indent
+.It MAKEDEV_REF
+reference the created device
+.It MAKEDEV_NOWAIT
+do not sleep, may return NULL
+.It MAKEDEV_WAITOK
+allow the function to sleep to satisfy malloc
+.It MAKEDEV_ETERNAL
+created device will be never destroyed
+.It MAKEDEV_CHECKNAME
+return NULL if the device name is invalid or already exists
+.El
 .Pp
 The
 .Dv MAKEDEV_WAITOK
@@ -166,6 +172,9 @@ For the convenience, use the
 flag for the code that can be compiled into kernel or loaded
 (and unloaded) as loadable module.
 .Pp
+A panic will occur if the MAKEDEV_CHECKNAME flag is not specified
+and the device name is invalid or already exists.
+.Pp
 The
 .Fn make_dev_cred
 function is equivalent to the call

Modified: head/sys/kern/kern_conf.c
==============================================================================
--- head/sys/kern/kern_conf.c	Thu Oct  7 17:49:19 2010	(r213525)
+++ head/sys/kern/kern_conf.c	Thu Oct  7 18:00:55 2010	(r213526)
@@ -682,26 +682,91 @@ prep_cdevsw(struct cdevsw *devsw, int fl
 }
 
 static int
+prep_devname(struct cdev *dev, const char *fmt, va_list ap)
+{
+	int len;
+	char *from, *q, *s, *to;
+
+	mtx_assert(&devmtx, MA_OWNED);
+
+	len = vsnrprintf(dev->__si_namebuf, sizeof(dev->__si_namebuf), 32,
+	    fmt, ap);
+	if (len > sizeof(dev->__si_namebuf) - 1)
+		return (ENAMETOOLONG);
+
+	/* Strip leading slashes. */
+	for (from = dev->__si_namebuf; *from == '/'; from++)
+		;
+
+	for (to = dev->__si_namebuf; *from != '\0'; from++, to++) {
+		/* Treat multiple sequential slashes as single. */
+		while (from[0] == '/' && from[1] == '/')
+			from++;
+		/* Trailing slash is considered invalid. */
+		if (from[0] == '/' && from[1] == '\0')
+			return (EINVAL);
+		*to = *from;
+	}
+	*to = '\0';
+
+	if (dev->__si_namebuf[0] == '\0')
+		return (EINVAL);
+
+	/* Disallow "." and ".." components. */
+	for (s = dev->__si_namebuf;;) {
+		for (q = s; *q != '/' && *q != '\0'; q++)
+			;
+		if (q - s == 1 && s[0] == '.')
+			return (EINVAL);
+		if (q - s == 2 && s[0] == '.' && s[1] == '.')
+			return (EINVAL);
+		if (*q != '/')
+			break;
+		s = q + 1;
+	}
+
+	if (devfs_dev_exists(dev->__si_namebuf) != 0)
+		return (EEXIST);
+
+	return (0);
+}
+
+static int
 make_dev_credv(int flags, struct cdev **dres, struct cdevsw *devsw, int unit,
     struct ucred *cr, uid_t uid, gid_t gid, int mode, const char *fmt,
     va_list ap)
 {
-	struct cdev *dev;
-	int i, res;
+	struct cdev *dev, *dev_new;
+	int res;
 
 	KASSERT((flags & MAKEDEV_WAITOK) == 0 || (flags & MAKEDEV_NOWAIT) == 0,
 	    ("make_dev_credv: both WAITOK and NOWAIT specified"));
-	dev = devfs_alloc(flags);
-	if (dev == NULL)
+	dev_new = devfs_alloc(flags);
+	if (dev_new == NULL)
 		return (ENOMEM);
 	dev_lock();
 	res = prep_cdevsw(devsw, flags);
 	if (res != 0) {
 		dev_unlock();
-		devfs_free(dev);
+		devfs_free(dev_new);
 		return (res);
 	}
-	dev = newdev(devsw, unit, dev);
+	dev = newdev(devsw, unit, dev_new);
+	if ((dev->si_flags & SI_NAMED) == 0)
+		res = prep_devname(dev, fmt, ap);
+		if (res != 0) {
+			if ((flags & MAKEDEV_CHECKNAME) == 0) {
+				panic(
+			"make_dev_credv: bad si_name (error=%d, si_name=%s)",
+				    res, dev->si_name);
+			}
+			if (dev == dev_new) {
+				LIST_REMOVE(dev, si_list);
+				dev_unlock();
+				devfs_free(dev);
+			}
+			return (res);
+	}
 	if (flags & MAKEDEV_REF)
 		dev_refl(dev);
 	if (flags & MAKEDEV_ETERNAL)
@@ -720,13 +785,6 @@ make_dev_credv(int flags, struct cdev **
 	KASSERT(!(dev->si_flags & SI_NAMED),
 	    ("make_dev() by driver %s on pre-existing device (min=%x, name=%s)",
 	    devsw->d_name, dev2unit(dev), devtoname(dev)));
-
-	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
-	if (i > (sizeof dev->__si_namebuf - 1)) {
-		printf("WARNING: Device name truncated! (%s)\n", 
-		    dev->__si_namebuf);
-	}
-		
 	dev->si_flags |= SI_NAMED;
 	if (cr != NULL)
 		dev->si_cred = crhold(cr);
@@ -756,7 +814,8 @@ make_dev(struct cdevsw *devsw, int unit,
 	res = make_dev_credv(0, &dev, devsw, unit, NULL, uid, gid, mode, fmt,
 	    ap);
 	va_end(ap);
-	KASSERT(res == 0 && dev != NULL, ("make_dev: failed make_dev_credv"));
+	KASSERT(res == 0 && dev != NULL,
+	    ("make_dev: failed make_dev_credv (error=%d)", res));
 	return (dev);
 }
 
@@ -773,7 +832,7 @@ make_dev_cred(struct cdevsw *devsw, int 
 	va_end(ap);
 
 	KASSERT(res == 0 && dev != NULL,
-	    ("make_dev_cred: failed make_dev_credv"));
+	    ("make_dev_cred: failed make_dev_credv (error=%d)", res));
 	return (dev);
 }
 
@@ -790,8 +849,9 @@ make_dev_credf(int flags, struct cdevsw 
 	    fmt, ap);
 	va_end(ap);
 
-	KASSERT((flags & MAKEDEV_NOWAIT) != 0 || res == 0,
-	    ("make_dev_credf: failed make_dev_credv"));
+	KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) ||
+	    ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0,
+	    ("make_dev_credf: failed make_dev_credv (error=%d)", res));
 	return (res == 0 ? dev : NULL);
 }
 
@@ -807,8 +867,9 @@ make_dev_p(int flags, struct cdev **cdev
 	    fmt, ap);
 	va_end(ap);
 
-	KASSERT((flags & MAKEDEV_NOWAIT) != 0 || res == 0,
-	    ("make_dev_p: failed make_dev_credv"));
+	KASSERT(((flags & MAKEDEV_NOWAIT) != 0 && res == ENOMEM) ||
+	    ((flags & MAKEDEV_CHECKNAME) != 0 && res != ENOMEM) || res == 0,
+	    ("make_dev_p: failed make_dev_credv (error=%d)", res));
 	return (res);
 }
 
@@ -836,21 +897,20 @@ make_dev_alias(struct cdev *pdev, const 
 {
 	struct cdev *dev;
 	va_list ap;
-	int i;
+	int error;
 
 	KASSERT(pdev != NULL, ("NULL pdev"));
 	dev = devfs_alloc(MAKEDEV_WAITOK);
 	dev_lock();
 	dev->si_flags |= SI_ALIAS;
-	dev->si_flags |= SI_NAMED;
 	va_start(ap, fmt);
-	i = vsnrprintf(dev->__si_namebuf, sizeof dev->__si_namebuf, 32, fmt, ap);
-	if (i > (sizeof dev->__si_namebuf - 1)) {
-		printf("WARNING: Device name truncated! (%s)\n", 
-		    dev->__si_namebuf);
-	}
+	error = prep_devname(dev, fmt, ap);
 	va_end(ap);
-
+	if (error != 0) {
+		panic("make_dev_alias: bad si_name (error=%d, si_name=%s)",
+		    error, dev->si_name);
+	}
+	dev->si_flags |= SI_NAMED;
 	devfs_create(dev);
 	dev_dependsl(pdev, dev);
 	clean_unrhdrl(devfs_inos);

Modified: head/sys/sys/conf.h
==============================================================================
--- head/sys/sys/conf.h	Thu Oct  7 17:49:19 2010	(r213525)
+++ head/sys/sys/conf.h	Thu Oct  7 18:00:55 2010	(r213526)
@@ -263,11 +263,12 @@ struct cdev *make_dev(struct cdevsw *_de
 struct cdev *make_dev_cred(struct cdevsw *_devsw, int _unit,
 		struct ucred *_cr, uid_t _uid, gid_t _gid, int _perms,
 		const char *_fmt, ...) __printflike(7, 8);
-#define	MAKEDEV_REF     0x01
-#define	MAKEDEV_WHTOUT	0x02
-#define	MAKEDEV_NOWAIT	0x04
-#define	MAKEDEV_WAITOK	0x08
-#define	MAKEDEV_ETERNAL	0x10
+#define	MAKEDEV_REF		0x01
+#define	MAKEDEV_WHTOUT		0x02
+#define	MAKEDEV_NOWAIT		0x04
+#define	MAKEDEV_WAITOK		0x08
+#define	MAKEDEV_ETERNAL		0x10
+#define	MAKEDEV_CHECKNAME	0x20
 struct cdev *make_dev_credf(int _flags,
 		struct cdevsw *_devsw, int _unit,
 		struct ucred *_cr, uid_t _uid, gid_t _gid, int _mode,



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201010071800.o97I0tiW048627>