Revert "mknod(2): Restrict functionality to creating FIFOs."
authorSascha Wildner <saw@online.de>
Thu, 20 Dec 2012 03:54:32 +0000 (04:54 +0100)
committerSascha Wildner <saw@online.de>
Thu, 20 Dec 2012 03:54:32 +0000 (04:54 +0100)
This reverts commit d5056fe0532f6e09c1c52b6384f3ef6e6db77a68.

After the commit, stuff like cpdup, tar, etc. used on dev would
start whining when before they would create the nodes, even
though they were not actually usable.

Since the potential breakage in external software is unknown, make
up my mind and go with the lower risk approach, even if it is kind
of pointless.

The mknod(8) utility is left deleted.

sys/emulation/linux/linux_misc.c
sys/kern/vfs_syscalls.c
sys/sys/kern_syscall.h

index 095d959..1d304e4 100644 (file)
@@ -1094,14 +1094,17 @@ sys_linux_mknod(struct linux_mknod_args *args)
                    path, args->mode, args->dev);
 #endif
        get_mplock();
-       if ((args->mode & S_IFIFO) == 0 || args->dev != 0) {
-               error = EINVAL;
-       } else {
-               error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
-               if (error == 0)
+       error = nlookup_init(&nd, path, UIO_SYSSPACE, 0);
+       if (error == 0) {
+               if (args->mode & S_IFIFO) {
                        error = kern_mkfifo(&nd, args->mode);
-               nlookup_done(&nd);
+               } else {
+                       error = kern_mknod(&nd, args->mode,
+                                          umajor(args->dev),
+                                          uminor(args->dev));
+               }
        }
+       nlookup_done(&nd);
        rel_mplock();
 
        linux_free_path(&path);
@@ -1125,15 +1128,18 @@ sys_linux_mknodat(struct linux_mknodat_args *args)
                    path, args->mode, args->dev);
 #endif
        get_mplock();
-       if ((args->mode & S_IFIFO) == 0 || args->dev != 0) {
-               error = EINVAL;
-       } else {
-               dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
-               error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, 0);
-               if (error == 0)
+       dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+       error = nlookup_init_at(&nd, &fp, dfd, path, UIO_SYSSPACE, 0);
+       if (error == 0) {
+               if (args->mode & S_IFIFO) {
                        error = kern_mkfifo(&nd, args->mode);
-               nlookup_done_at(&nd, fp);
+               } else {
+                       error = kern_mknod(&nd, args->mode,
+                                          umajor(args->dev),
+                                          uminor(args->dev));
+               }
        }
+       nlookup_done_at(&nd, fp);
        rel_mplock();
 
        linux_free_path(&path);
index e66090e..dc144d2 100644 (file)
@@ -1976,6 +1976,74 @@ sys_openat(struct openat_args *uap)
        return (error);
 }
 
+int
+kern_mknod(struct nlookupdata *nd, int mode, int rmajor, int rminor)
+{
+       struct thread *td = curthread;
+       struct proc *p = td->td_proc;
+       struct vnode *vp;
+       struct vattr vattr;
+       int error;
+       int whiteout = 0;
+
+       KKASSERT(p);
+
+       VATTR_NULL(&vattr);
+       vattr.va_mode = (mode & ALLPERMS) &~ p->p_fd->fd_cmask;
+       vattr.va_rmajor = rmajor;
+       vattr.va_rminor = rminor;
+
+       switch (mode & S_IFMT) {
+       case S_IFMT:    /* used by badsect to flag bad sectors */
+               error = priv_check_cred(td->td_ucred, PRIV_VFS_MKNOD_BAD, 0);
+               vattr.va_type = VBAD;
+               break;
+       case S_IFCHR:
+               error = priv_check(td, PRIV_VFS_MKNOD_DEV);
+               vattr.va_type = VCHR;
+               break;
+       case S_IFBLK:
+               error = priv_check(td, PRIV_VFS_MKNOD_DEV);
+               vattr.va_type = VBLK;
+               break;
+       case S_IFWHT:
+               error = priv_check_cred(td->td_ucred, PRIV_VFS_MKNOD_WHT, 0);
+               whiteout = 1;
+               break;
+       case S_IFDIR:   /* special directories support for HAMMER */
+               error = priv_check_cred(td->td_ucred, PRIV_VFS_MKNOD_DIR, 0);
+               vattr.va_type = VDIR;
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
+
+       if (error)
+               return (error);
+
+       bwillinode(1);
+       nd->nl_flags |= NLC_CREATE | NLC_REFDVP;
+       if ((error = nlookup(nd)) != 0)
+               return (error);
+       if (nd->nl_nch.ncp->nc_vp)
+               return (EEXIST);
+       if ((error = ncp_writechk(&nd->nl_nch)) != 0)
+               return (error);
+
+       if (whiteout) {
+               error = VOP_NWHITEOUT(&nd->nl_nch, nd->nl_dvp,
+                                     nd->nl_cred, NAMEI_CREATE);
+       } else {
+               vp = NULL;
+               error = VOP_NMKNOD(&nd->nl_nch, nd->nl_dvp,
+                                  &vp, nd->nl_cred, &vattr);
+               if (error == 0)
+                       vput(vp);
+       }
+       return (error);
+}
+
 /*
  * mknod_args(char *path, int mode, int dev)
  *
@@ -1987,14 +2055,12 @@ sys_mknod(struct mknod_args *uap)
        struct nlookupdata nd;
        int error;
 
-       if ((uap->mode & S_IFIFO) == 0 || uap->dev != 0) {
-               error = EINVAL;
-       } else {
-               error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0);
-               if (error == 0)
-                       error = kern_mkfifo(&nd, uap->mode);
-               nlookup_done(&nd);
+       error = nlookup_init(&nd, uap->path, UIO_USERSPACE, 0);
+       if (error == 0) {
+               error = kern_mknod(&nd, uap->mode,
+                                  umajor(uap->dev), uminor(uap->dev));
        }
+       nlookup_done(&nd);
        return (error);
 }
 
@@ -2011,15 +2077,12 @@ sys_mknodat(struct mknodat_args *uap)
        struct file *fp;
        int error;
 
-       if ((uap->mode & S_IFIFO) == 0 || uap->dev != 0) {
-               error = EINVAL;
-       } else {
-               error = nlookup_init_at(&nd, &fp, uap->fd, uap->path,
-                   UIO_USERSPACE, 0);
-               if (error == 0)
-                       error = kern_mkfifo(&nd, uap->mode);
-               nlookup_done_at(&nd, fp);
+       error = nlookup_init_at(&nd, &fp, uap->fd, uap->path, UIO_USERSPACE, 0);
+       if (error == 0) {
+               error = kern_mknod(&nd, uap->mode,
+                                  umajor(uap->dev), uminor(uap->dev));
        }
+       nlookup_done_at(&nd, fp);
        return (error);
 }
 
index ffff2cf..6e3cacf 100644 (file)
@@ -148,6 +148,7 @@ int kern_mountctl(const char *path, int op, struct file *fp,
                 void *buf, int buflen, int *res);
 int kern_mkdir(struct nlookupdata *nd, int mode);
 int kern_mkfifo(struct nlookupdata *nd, int mode);
+int kern_mknod(struct nlookupdata *nd, int mode, int rmajor, int rminor);
 int kern_open(struct nlookupdata *nd, int flags, int mode, int *res);
 int kern_close(int fd);
 int kern_closefrom(int fd);