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>