···6363 return -EINVAL;64646565 spin_lock(&files->file_lock);6666- if (!(file = fcheck(oldfd)))6767- goto out_unlock;6868- get_file(file); /* We are now finished with oldfd */6969-7066 err = expand_files(files, newfd);6767+ file = fcheck(oldfd);6868+ if (unlikely(!file))6969+ goto Ebadf;7170 if (unlikely(err < 0)) {7271 if (err == -EMFILE)7373- err = -EBADF;7474- goto out_fput;7272+ goto Ebadf;7373+ goto out_unlock;7574 }7676-7777- /* To avoid races with open() and dup(), we will mark the fd as7878- * in-use in the open-file bitmap throughout the entire dup2()7979- * process. This is quite safe: do_close() uses the fd array8080- * entry, not the bitmap, to decide what work needs to be8181- * done. --sct */8282- /* Doesn't work. open() might be there first. --AV */8383-8484- /* Yes. It's a race. In user space. Nothing sane to do */7575+ /*7676+ * We need to detect attempts to do dup2() over allocated but still7777+ * not finished descriptor. NB: OpenBSD avoids that at the price of7878+ * extra work in their equivalent of fget() - they insert struct7979+ * file immediately after grabbing descriptor, mark it larval if8080+ * more work (e.g. actual opening) is needed and make sure that8181+ * fget() treats larval files as absent. Potentially interesting,8282+ * but while extra work in fget() is trivial, locking implications8383+ * and amount of surgery on open()-related paths in VFS are not.8484+ * FreeBSD fails with -EBADF in the same situation, NetBSD "solution"8585+ * deadlocks in rather amusing ways, AFAICS. All of that is out of8686+ * scope of POSIX or SUS, since neither considers shared descriptor8787+ * tables and this condition does not arise without those.8888+ */8589 err = -EBUSY;8690 fdt = files_fdtable(files);8791 tofree = fdt->fd[newfd];8892 if (!tofree && FD_ISSET(newfd, fdt->open_fds))8989- goto out_fput;9090-9393+ goto out_unlock;9494+ get_file(file);9195 rcu_assign_pointer(fdt->fd[newfd], file);9296 FD_SET(newfd, fdt->open_fds);9397 if (flags & O_CLOEXEC)···1029810399 if (tofree)104100 filp_close(tofree, files);105105- err = newfd;106106-out:107107- return err;101101+102102+ return newfd;103103+104104+Ebadf:105105+ err = -EBADF;108106out_unlock:109107 spin_unlock(&files->file_lock);110110- goto out;111111-112112-out_fput:113113- spin_unlock(&files->file_lock);114114- fput(file);115115- goto out;108108+ return err;116109}117110118111asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)