[v3,01/15] files: Fix find_unused_fd() overflow

Submitted by Kirill Tkhai on June 1, 2016, 3:11 p.m.

Details

Message ID 146479387238.19418.6910855296550565951.stgit@pro
State Accepted
Series "Support for packet's msg_name in receive queue of promiscous DGRAM sockets"
Commit 1aa8281a4fa215c0e5620adf419225dd8c747d9a
Headers show

Commit Message

Kirill Tkhai June 1, 2016, 3:11 p.m.
This function may catch overflow near INT_MAX, so
it becomes return strange fd, like fd = -2147483648.
Fix that.

Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
---
 criu/files.c             |   25 +++++++++++++++++++++++++
 criu/include/files.h     |    8 +-------
 criu/include/servicefd.h |    1 +
 criu/util.c              |    5 +++++
 4 files changed, 32 insertions(+), 7 deletions(-)

Patch hide | download patch | download mbox

diff --git a/criu/files.c b/criu/files.c
index 16bc74d..15306d6 100644
--- a/criu/files.c
+++ b/criu/files.c
@@ -97,6 +97,31 @@  static inline struct file_desc *find_file_desc(FdinfoEntry *fe)
 	return find_file_desc_raw(fe->type, fe->id);
 }
 
+unsigned int find_unused_fd(struct list_head *head, int hint_fd)
+{
+	struct fdinfo_list_entry *fle;
+	int fd = 0, prev_fd;
+
+	if ((hint_fd >= 0) && (!fd_is_used(head, hint_fd))) {
+		fd = hint_fd;
+		goto out;
+	}
+
+	prev_fd = service_fd_min_fd() - 1;
+
+	list_for_each_entry_reverse(fle, head, used_list) {
+		fd = fle->fe->fd;
+		if (prev_fd > fd) {
+			fd++;
+			goto out;
+		}
+		prev_fd = fd - 1;
+	}
+	BUG();
+out:
+	return fd;
+}
+
 /*
  * A file may be shared between several file descriptors. E.g
  * when doing a fork() every fd of a forker and respective fds
diff --git a/criu/include/files.h b/criu/include/files.h
index f89164e..d46b3cd 100644
--- a/criu/include/files.h
+++ b/criu/include/files.h
@@ -137,13 +137,7 @@  static inline bool fd_is_used(struct list_head *head, int fd)
 	return false;
 }
 
-static inline unsigned int find_unused_fd(struct list_head *head, int hint_fd)
-{
-	if ((hint_fd >= 0) && (!fd_is_used(head, hint_fd)))
-		return hint_fd;
-	/* Return last used fd +1 */
-	return list_entry(head->prev, typeof(struct fdinfo_list_entry), used_list)->fe->fd + 1;
-}
+unsigned int find_unused_fd(struct list_head *head, int hint_fd);
 
 struct file_desc {
 	u32			id;		/* File id, unique */
diff --git a/criu/include/servicefd.h b/criu/include/servicefd.h
index a9e35a2..e133752 100644
--- a/criu/include/servicefd.h
+++ b/criu/include/servicefd.h
@@ -31,5 +31,6 @@  extern int install_service_fd(enum sfd_type type, int fd);
 extern int close_service_fd(enum sfd_type type);
 extern bool is_service_fd(int fd, enum sfd_type type);
 extern bool is_any_service_fd(int fd);
+extern int service_fd_min_fd(void);
 
 #endif /* __CR_SERVICE_FD_H__ */
diff --git a/criu/util.c b/criu/util.c
index f518847..ff5184c 100644
--- a/criu/util.c
+++ b/criu/util.c
@@ -409,6 +409,11 @@  static int __get_service_fd(enum sfd_type type, int service_fd_id)
 	return service_fd_rlim_cur - type - SERVICE_FD_MAX * service_fd_id;
 }
 
+int service_fd_min_fd(void)
+{
+	return service_fd_rlim_cur - (SERVICE_FD_MAX - 1) - SERVICE_FD_MAX * service_fd_id;
+}
+
 static DECLARE_BITMAP(sfd_map, SERVICE_FD_MAX);
 
 int reserve_service_fd(enum sfd_type type)