[5/6] kdat: Check for KCMP_EPOLL_TFD

Submitted by Cyrill Gorcunov on April 3, 2018, 5:46 p.m.

Details

Message ID 20180403174650.30628-6-gorcunov@gmail.com
State Rejected
Series "Preparatory patches for handling duped tfd on epoll"
Headers show

Commit Message

Cyrill Gorcunov April 3, 2018, 5:46 p.m.
This feature will be needed to support duplicated
target file descriptors in epoll.

Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
---
 criu/include/kcmp.h    | 10 ++++++++
 criu/include/kerndat.h |  1 +
 criu/kerndat.c         | 64 +++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 74 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/criu/include/kcmp.h b/criu/include/kcmp.h
index 76f557bff047..b6d3519a0c5c 100644
--- a/criu/include/kcmp.h
+++ b/criu/include/kcmp.h
@@ -1,6 +1,8 @@ 
 #ifndef __CR_KCMP_H__
 #define __CR_KCMP_H__
 
+#include <stdint.h>
+
 enum kcmp_type {
 	KCMP_FILE,
 	KCMP_VM,
@@ -9,8 +11,16 @@  enum kcmp_type {
 	KCMP_SIGHAND,
 	KCMP_IO,
 	KCMP_SYSVSEM,
+	KCMP_EPOLL_TFD,
 
 	KCMP_TYPES,
 };
 
+/* Slot for KCMP_EPOLL_TFD */
+typedef struct {
+	uint32_t efd;		/* epoll file descriptor */
+	uint32_t tfd;		/* target file number */
+	uint32_t toff;		/* target offset within same numbered sequence */
+} kcmp_epoll_slot_t;
+
 #endif /* __CR_KCMP_H__ */
diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
index 28a84fb0d583..af6b5c5c3a38 100644
--- a/criu/include/kerndat.h
+++ b/criu/include/kerndat.h
@@ -77,6 +77,7 @@  struct kerndat_s {
 	bool has_pid_for_children_ns;
 	bool x86_has_ptrace_fpu_xsave_bug;
 	bool has_inotify_setnextwd;
+	bool has_kcmp_epoll_tfd;
 };
 
 extern struct kerndat_s kdat;
diff --git a/criu/kerndat.c b/criu/kerndat.c
index 227d429f9dde..456adbf2851f 100644
--- a/criu/kerndat.c
+++ b/criu/kerndat.c
@@ -13,7 +13,7 @@ 
 #include <arpa/inet.h>  /* for sockaddr_in and inet_ntoa() */
 #include <sys/prctl.h>
 #include <sys/inotify.h>
-
+#include <sys/epoll.h>
 
 #include "common/config.h"
 #include "int.h"
@@ -40,6 +40,7 @@ 
 #include "prctl.h"
 #include "uffd.h"
 #include "vdso.h"
+#include "kcmp.h"
 
 struct kerndat_s kdat = {
 };
@@ -819,6 +820,65 @@  int kerndat_has_inotify_setnextwd(void)
 	return ret;
 }
 
+static int kerndat_has_kcmp_epoll_tfd(void)
+{
+	kcmp_epoll_slot_t epoll_slot = { };
+	struct epoll_event ev;
+	int ret = -1;
+	int pipefd[2];
+	int epollfd;
+	int fddup;
+
+	if (pipe(pipefd)) {
+		pr_perror("Can't create pipe");
+		return -1;
+	}
+
+	epollfd = epoll_create1(0);
+	if (epollfd < 0) {
+		pr_perror("epoll_create1 failed");
+		return -1;
+	}
+
+	memset(&ev, 0xff, sizeof(ev));
+	ev.events = EPOLLIN | EPOLLOUT;
+
+	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd[0], &ev)) {
+		pr_perror("epoll_ctl failed");
+		return -1;
+	}
+
+	fddup = dup(pipefd[1]);
+	if (fddup < 0) {
+		pr_perror("dup2 failed");
+		goto out;
+	}
+
+	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fddup, &ev)) {
+		pr_perror("epoll_ctl failed");
+		close(fddup);
+		goto out;
+	}
+	close(fddup);
+
+	epoll_slot = (kcmp_epoll_slot_t) {
+		.efd	= epollfd,
+		.tfd	= fddup,
+		.toff	= 0,
+	};
+
+	ret = syscall(SYS_kcmp, getpid(), getpid(),
+		      KCMP_EPOLL_TFD, pipefd[1], (void *)&epoll_slot);
+	if (ret == 0)
+		kdat.has_kcmp_epoll_tfd = true;
+
+out:
+	close(pipefd[0]);
+	close(pipefd[1]);
+	close(epollfd);
+	return ret;
+}
+
 int __attribute__((weak)) kdat_x86_has_ptrace_fpu_xsave_bug(void)
 {
 	return 0;
@@ -1124,6 +1184,8 @@  int kerndat_init(void)
 		ret = kerndat_x86_has_ptrace_fpu_xsave_bug();
 	if (!ret)
 		ret = kerndat_has_inotify_setnextwd();
+	if (!ret)
+		ret = kerndat_has_kcmp_epoll_tfd();
 
 	kerndat_lsm();
 	kerndat_mmap_min_addr();

Comments

Dmitry Safonov April 3, 2018, 6:01 p.m.
Hi Cyrill,

Thanks for splitting this and adding kdat feature first,

2018-04-03 18:46 GMT+01:00 Cyrill Gorcunov <gorcunov@gmail.com>:
[..]
> +
> +       ret = syscall(SYS_kcmp, getpid(), getpid(),
> +                     KCMP_EPOLL_TFD, pipefd[1], (void *)&epoll_slot);
> +       if (ret == 0)
> +               kdat.has_kcmp_epoll_tfd = true;
> +
> +out:
> +       close(pipefd[0]);
> +       close(pipefd[1]);
> +       close(epollfd);
> +       return ret;

Does that mean that if kcmp() with KCMP_EPOLL_TFD fails
(no support for the feature), than kerndat_has_kcmp_epoll_tfd() will return
error - which will lead to stopping generating kdat and aborting, rather than
proceeding with kdat.has_kcmp_epoll_tfd = false?

> +}
> +
>  int __attribute__((weak)) kdat_x86_has_ptrace_fpu_xsave_bug(void)
>  {
>         return 0;
> @@ -1124,6 +1184,8 @@ int kerndat_init(void)
>                 ret = kerndat_x86_has_ptrace_fpu_xsave_bug();
>         if (!ret)
>                 ret = kerndat_has_inotify_setnextwd();
> +       if (!ret)
> +               ret = kerndat_has_kcmp_epoll_tfd();
>
>         kerndat_lsm();
>         kerndat_mmap_min_addr();
Cyrill Gorcunov April 3, 2018, 6:04 p.m.
On Tue, Apr 03, 2018 at 07:01:36PM +0100, Dmitry Safonov wrote:
> 
> Does that mean that if kcmp() with KCMP_EPOLL_TFD fails
> (no support for the feature), than kerndat_has_kcmp_epoll_tfd() will return
> error - which will lead to stopping generating kdat and aborting, rather than
> proceeding with kdat.has_kcmp_epoll_tfd = false?

Good spot! Surely we need to proceed with feature disabled.
Andrew, if you agree on the rest of the patches, how would
be preferred to send the fix, as sole patch or as a separate
one on top of this series with only small fix?
Andrey Vagin April 5, 2018, 11:05 p.m.
On Tue, Apr 03, 2018 at 08:46:49PM +0300, Cyrill Gorcunov wrote:
> This feature will be needed to support duplicated
> target file descriptors in epoll.
> 
> Signed-off-by: Cyrill Gorcunov <gorcunov@gmail.com>
> ---
>  criu/include/kcmp.h    | 10 ++++++++
>  criu/include/kerndat.h |  1 +
>  criu/kerndat.c         | 64 +++++++++++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 74 insertions(+), 1 deletion(-)
> 
> diff --git a/criu/include/kcmp.h b/criu/include/kcmp.h
> index 76f557bff047..b6d3519a0c5c 100644
> --- a/criu/include/kcmp.h
> +++ b/criu/include/kcmp.h
> @@ -1,6 +1,8 @@
>  #ifndef __CR_KCMP_H__
>  #define __CR_KCMP_H__
>  
> +#include <stdint.h>
> +
>  enum kcmp_type {
>  	KCMP_FILE,
>  	KCMP_VM,
> @@ -9,8 +11,16 @@ enum kcmp_type {
>  	KCMP_SIGHAND,
>  	KCMP_IO,
>  	KCMP_SYSVSEM,
> +	KCMP_EPOLL_TFD,
>  
>  	KCMP_TYPES,
>  };
>  
> +/* Slot for KCMP_EPOLL_TFD */
> +typedef struct {
> +	uint32_t efd;		/* epoll file descriptor */
> +	uint32_t tfd;		/* target file number */
> +	uint32_t toff;		/* target offset within same numbered sequence */
> +} kcmp_epoll_slot_t;
> +
>  #endif /* __CR_KCMP_H__ */
> diff --git a/criu/include/kerndat.h b/criu/include/kerndat.h
> index 28a84fb0d583..af6b5c5c3a38 100644
> --- a/criu/include/kerndat.h
> +++ b/criu/include/kerndat.h
> @@ -77,6 +77,7 @@ struct kerndat_s {
>  	bool has_pid_for_children_ns;
>  	bool x86_has_ptrace_fpu_xsave_bug;
>  	bool has_inotify_setnextwd;
> +	bool has_kcmp_epoll_tfd;
>  };
>  
>  extern struct kerndat_s kdat;
> diff --git a/criu/kerndat.c b/criu/kerndat.c
> index 227d429f9dde..456adbf2851f 100644
> --- a/criu/kerndat.c
> +++ b/criu/kerndat.c
> @@ -13,7 +13,7 @@
>  #include <arpa/inet.h>  /* for sockaddr_in and inet_ntoa() */
>  #include <sys/prctl.h>
>  #include <sys/inotify.h>
> -
> +#include <sys/epoll.h>
>  
>  #include "common/config.h"
>  #include "int.h"
> @@ -40,6 +40,7 @@
>  #include "prctl.h"
>  #include "uffd.h"
>  #include "vdso.h"
> +#include "kcmp.h"
>  
>  struct kerndat_s kdat = {
>  };
> @@ -819,6 +820,65 @@ int kerndat_has_inotify_setnextwd(void)
>  	return ret;
>  }
>  
> +static int kerndat_has_kcmp_epoll_tfd(void)
> +{
> +	kcmp_epoll_slot_t epoll_slot = { };
> +	struct epoll_event ev;
> +	int ret = -1;
> +	int pipefd[2];
> +	int epollfd;
> +	int fddup;
> +
> +	if (pipe(pipefd)) {
> +		pr_perror("Can't create pipe");
> +		return -1;
> +	}
> +
> +	epollfd = epoll_create1(0);
> +	if (epollfd < 0) {

pipefd descriptors leaks

> +		pr_perror("epoll_create1 failed");
> +		return -1;
> +	}
> +
> +	memset(&ev, 0xff, sizeof(ev));
> +	ev.events = EPOLLIN | EPOLLOUT;
> +
> +	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd[0], &ev)) {
> +		pr_perror("epoll_ctl failed");

leak opened descriptors

> +		return -1;
> +	}
> +
> +	fddup = dup(pipefd[1]);
> +	if (fddup < 0) {
> +		pr_perror("dup2 failed");
> +		goto out;
> +	}
> +
> +	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fddup, &ev)) {
> +		pr_perror("epoll_ctl failed");
> +		close(fddup);
> +		goto out;
> +	}
> +	close(fddup);
> +
> +	epoll_slot = (kcmp_epoll_slot_t) {
> +		.efd	= epollfd,
> +		.tfd	= fddup,
> +		.toff	= 0,
> +	};
> +
> +	ret = syscall(SYS_kcmp, getpid(), getpid(),
> +		      KCMP_EPOLL_TFD, pipefd[1], (void *)&epoll_slot);
> +	if (ret == 0)
> +		kdat.has_kcmp_epoll_tfd = true;
> +
> +out:
> +	close(pipefd[0]);
> +	close(pipefd[1]);
> +	close(epollfd);
> +	return ret;
> +}
> +
>  int __attribute__((weak)) kdat_x86_has_ptrace_fpu_xsave_bug(void)
>  {
>  	return 0;
> @@ -1124,6 +1184,8 @@ int kerndat_init(void)
>  		ret = kerndat_x86_has_ptrace_fpu_xsave_bug();
>  	if (!ret)
>  		ret = kerndat_has_inotify_setnextwd();
> +	if (!ret)
> +		ret = kerndat_has_kcmp_epoll_tfd();
>  
>  	kerndat_lsm();
>  	kerndat_mmap_min_addr();
> -- 
> 2.14.3
> 
> _______________________________________________
> CRIU mailing list
> CRIU@openvz.org
> https://lists.openvz.org/mailman/listinfo/criu