lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Fri, 28 Apr 2017 00:44:45 +0530
From:   Sandhya Bankar <bankarsandhya512@...il.com>
To:     linux-fsdevel@...r.kernel.org, linux-kernel@...r.kernel.org,
        viro@...iv.linux.org.uk, mawmilcox@...rosoft.com,
        keescook@...omium.org, adobriyan@...il.com, re.emese@...il.com,
        riel@...riel.com
Subject: [PATCH 10/13] vfs: Replace close_on_exec bitmap with an IDR tag

Replace close_on_exec with idr_(get,set,clear)_tag().
Through this patch, added new IDR tag FD_TAG_CLOEXEC
which is passing to idr_(get,set,clear)_tag() to
achieve close_on_exec functionality.
Also removed get_close_on_exec() and using close_on_exec() instead of that.

Signed-off-by: Sandhya Bankar <bankarsandhya512@...il.com>
Signed-off-by: Matthew Wilcox <mawilcox@...rosoft.com>
---
 fs/exec.c               |  2 +-
 fs/fcntl.c              |  2 +-
 fs/file.c               | 85 +++++++++++++++----------------------------------
 fs/proc/fd.c            |  4 +--
 include/linux/fdtable.h | 19 +++++++----
 include/linux/file.h    |  1 -
 6 files changed, 41 insertions(+), 72 deletions(-)

diff --git a/fs/exec.c b/fs/exec.c
index 65145a3..2070bc6 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1728,7 +1728,7 @@ static int do_execveat_common(int fd, struct filename *filename,
 		 * inaccessible after exec. Relies on having exclusive access to
 		 * current->files (due to unshare_files above).
 		 */
-		if (close_on_exec(fd, rcu_dereference_raw(current->files->fdt)))
+		if (close_on_exec(fd, current->files))
 			bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE;
 		bprm->filename = pathbuf;
 	}
diff --git a/fs/fcntl.c b/fs/fcntl.c
index be8fbe2..9c2061b 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -255,7 +255,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
 		err = f_dupfd(arg, filp, O_CLOEXEC);
 		break;
 	case F_GETFD:
-		err = get_close_on_exec(fd) ? FD_CLOEXEC : 0;
+		err = close_on_exec(fd, current->files) ? FD_CLOEXEC : 0;
 		break;
 	case F_SETFD:
 		err = 0;
diff --git a/fs/file.c b/fs/file.c
index 8cd77c5..56c5731 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -70,8 +70,6 @@ static void copy_fd_bitmaps(struct fdtable *nfdt, struct fdtable *ofdt,
 	set = (nfdt->max_fds - count) / BITS_PER_BYTE;
 	memcpy(nfdt->open_fds, ofdt->open_fds, cpy);
 	memset((char *)nfdt->open_fds + cpy, 0, set);
-	memcpy(nfdt->close_on_exec, ofdt->close_on_exec, cpy);
-	memset((char *)nfdt->close_on_exec + cpy, 0, set);
 }
 
 /*
@@ -115,13 +113,10 @@ static struct fdtable * alloc_fdtable(unsigned int nr)
 		goto out;
 	fdt->max_fds = nr;
 
-	data = alloc_fdmem(max_t(size_t,
-				 2 * nr / BITS_PER_BYTE, L1_CACHE_BYTES));
+	data = alloc_fdmem(max_t(size_t, nr / BITS_PER_BYTE, L1_CACHE_BYTES));
 	if (!data)
 		goto out_fdt;
 	fdt->open_fds = data;
-	data += nr / BITS_PER_BYTE;
-	fdt->close_on_exec = data;
 
 	return fdt;
 
@@ -227,15 +222,16 @@ static inline bool fd_is_open(unsigned int fd, struct files_struct *files)
 	return !idr_tag_get(&files->fd_idr, fd, IDR_FREE);
 }
 
-static inline void __set_close_on_exec(unsigned int fd, struct fdtable *fdt)
+static inline void __set_close_on_exec(unsigned int fd,
+					struct files_struct *files)
 {
-	__set_bit(fd, fdt->close_on_exec);
+	idr_tag_set(&files->fd_idr, fd, FD_TAG_CLOEXEC);
 }
 
-static inline void __clear_close_on_exec(unsigned int fd, struct fdtable *fdt)
+static inline void __clear_close_on_exec(unsigned int fd,
+					 struct files_struct *files)
 {
-	if (test_bit(fd, fdt->close_on_exec))
-		__clear_bit(fd, fdt->close_on_exec);
+	idr_tag_clear(&files->fd_idr, fd, FD_TAG_CLOEXEC);
 }
 
 static inline void __set_open_fd(unsigned int fd, struct fdtable *fdt)
@@ -287,7 +283,6 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
 	init_waitqueue_head(&newf->resize_wait);
 	new_fdt = &newf->fdtab;
 	new_fdt->max_fds = NR_OPEN_DEFAULT;
-	new_fdt->close_on_exec = newf->close_on_exec_init;
 	new_fdt->open_fds = newf->open_fds_init;
 
 restart:
@@ -347,6 +342,9 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp)
 			spin_unlock(&oldf->file_lock);
 			goto out;
 		}
+
+		if (idr_tag_get(&oldf->fd_idr, i, FD_TAG_CLOEXEC))
+			idr_tag_set(&newf->fd_idr, i, FD_TAG_CLOEXEC);
 	}
 
 	spin_unlock(&oldf->file_lock);
@@ -445,7 +443,6 @@ struct files_struct init_files = {
 	.fdt		= &init_files.fdtab,
 	.fdtab		= {
 		.max_fds	= NR_OPEN_DEFAULT,
-		.close_on_exec	= init_files.close_on_exec_init,
 		.open_fds	= init_files.open_fds_init,
 	},
 	.file_lock	= __SPIN_LOCK_UNLOCKED(init_files.file_lock),
@@ -482,9 +479,9 @@ int __alloc_fd(struct files_struct *files,
 	fdt = files_fdtable(files);
 	__set_open_fd(fd, fdt);
 	if (flags & O_CLOEXEC)
-		__set_close_on_exec(fd, fdt);
+		__set_close_on_exec(fd, files);
 	else
-		__clear_close_on_exec(fd, fdt);
+		__clear_close_on_exec(fd, files);
 	error = fd;
 
 out:
@@ -571,7 +568,7 @@ int __close_fd(struct files_struct *files, unsigned fd)
 	file = idr_remove(&files->fd_idr, fd);
 	if (!file)
 		goto out_unlock;
-	__clear_close_on_exec(fd, fdt);
+	__clear_close_on_exec(fd, files);
 	__put_unused_fd(files, fd);
 	spin_unlock(&files->file_lock);
 	return filp_close(file, files);
@@ -583,35 +580,19 @@ int __close_fd(struct files_struct *files, unsigned fd)
 
 void do_close_on_exec(struct files_struct *files)
 {
-	unsigned i;
-	struct fdtable *fdt;
+	struct file *file;
+	unsigned int fd;
 
 	/* exec unshares first */
 	spin_lock(&files->file_lock);
-	for (i = 0; ; i++) {
-		unsigned long set;
-		unsigned fd = i * BITS_PER_LONG;
-		fdt = files_fdtable(files);
-		if (fd >= fdt->max_fds)
-			break;
-		set = fdt->close_on_exec[i];
-		if (!set)
-			continue;
-		fdt->close_on_exec[i] = 0;
-		for ( ; set ; fd++, set >>= 1) {
-			struct file *file;
-			if (!(set & 1))
-				continue;
-			file = idr_remove(&files->fd_idr, fd);
-			if (!file)
-				continue;
-			__put_unused_fd(files, fd);
-			spin_unlock(&files->file_lock);
-			filp_close(file, files);
-			cond_resched();
-			spin_lock(&files->file_lock);
-		}
 
+	idr_for_each_entry_tagged(&files->fd_idr, file, fd, FD_TAG_CLOEXEC) {
+		idr_remove(&files->fd_idr, fd);
+		__put_unused_fd(files, fd);
+		spin_unlock(&files->file_lock);
+		filp_close(file, files);
+		cond_resched();
+		spin_lock(&files->file_lock);
 	}
 	spin_unlock(&files->file_lock);
 }
@@ -723,28 +704,14 @@ void __f_unlock_pos(struct file *f)
 void set_close_on_exec(unsigned int fd, int flag)
 {
 	struct files_struct *files = current->files;
-	struct fdtable *fdt;
 	spin_lock(&files->file_lock);
-	fdt = files_fdtable(files);
 	if (flag)
-		__set_close_on_exec(fd, fdt);
+		__set_close_on_exec(fd, files);
 	else
-		__clear_close_on_exec(fd, fdt);
+		__clear_close_on_exec(fd, files);
 	spin_unlock(&files->file_lock);
 }
 
-bool get_close_on_exec(unsigned int fd)
-{
-	struct files_struct *files = current->files;
-	struct fdtable *fdt;
-	bool res;
-	rcu_read_lock();
-	fdt = files_fdtable(files);
-	res = close_on_exec(fd, fdt);
-	rcu_read_unlock();
-	return res;
-}
-
 static int do_dup2(struct files_struct *files,
 	struct file *file, unsigned fd, unsigned flags)
 __releases(&files->file_lock)
@@ -783,9 +750,9 @@ static int do_dup2(struct files_struct *files,
 	}
 	__set_open_fd(fd, fdt);
 	if (flags & O_CLOEXEC)
-		__set_close_on_exec(fd, fdt);
+		__set_close_on_exec(fd, files);
 	else
-		__clear_close_on_exec(fd, fdt);
+		__clear_close_on_exec(fd, files);
 	spin_unlock(&files->file_lock);
 	idr_preload_end();
 
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index c330495..2735ccc 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -36,10 +36,8 @@ static int seq_show(struct seq_file *m, void *v)
 		spin_lock(&files->file_lock);
 		file = fcheck_files(files, fd);
 		if (file) {
-			struct fdtable *fdt = files_fdtable(files);
-
 			f_flags = file->f_flags;
-			if (close_on_exec(fd, fdt))
+			if (close_on_exec(fd, files))
 				f_flags |= O_CLOEXEC;
 
 			get_file(file);
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index 67259f4..7f1ab82 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -22,18 +22,14 @@
  */
 #define NR_OPEN_DEFAULT BITS_PER_LONG
 
+#define	FD_TAG_CLOEXEC	1
+
 struct fdtable {
 	unsigned int max_fds;
-	unsigned long *close_on_exec;
 	unsigned long *open_fds;
 	struct rcu_head rcu;
 };
 
-static inline bool close_on_exec(unsigned int fd, const struct fdtable *fdt)
-{
-	return test_bit(fd, fdt->close_on_exec);
-}
-
 /*
  * Open file table structure
  */
@@ -52,7 +48,6 @@ struct files_struct {
    * written part on a separate cache line in SMP
    */
 	spinlock_t file_lock ____cacheline_aligned_in_smp;
-	unsigned long close_on_exec_init[1];
 	unsigned long open_fds_init[1];
 };
 
@@ -82,6 +77,16 @@ static inline struct file *fcheck_files(struct files_struct *files, unsigned int
 	return __fcheck_files(files, fd);
 }
 
+static inline bool close_on_exec(unsigned int fd, struct files_struct *files)
+{
+	bool res;
+
+	rcu_read_lock();
+	res = idr_tag_get(&files->fd_idr, fd, FD_TAG_CLOEXEC);
+	rcu_read_unlock();
+	return res;
+}
+
 /*
  * Check whether the specified fd has an open file.
  */
diff --git a/include/linux/file.h b/include/linux/file.h
index 61eb82c..1856bbf 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -76,7 +76,6 @@ static inline void fdput_pos(struct fd f)
 extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
 extern int replace_fd(unsigned fd, struct file *file, unsigned flags);
 extern void set_close_on_exec(unsigned int fd, int flag);
-extern bool get_close_on_exec(unsigned int fd);
 extern void put_filp(struct file *);
 extern int get_unused_fd_flags(unsigned flags);
 extern void put_unused_fd(unsigned int fd);
-- 
1.8.3.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ