aboutsummaryrefslogtreecommitdiffstats
path: root/main/lxc/re-exec-of-liblxc.patch
blob: ed31bd389bf805ce36350d8e3fe7ee0ed81e897b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
From d3a9befc86113228f77c89030336faa84a5557c0 Mon Sep 17 00:00:00 2001
From: Christian Brauner <christian.brauner@ubuntu.com>
Date: Tue, 12 Feb 2019 17:31:14 +0100
Subject: [PATCH] rexec: make rexecution opt-in for library callers
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

We cannot rexecute the liblxc shared library unconditionally as this would
break most of our downstreams. Here are some scenarios:
- anyone performing a dlopen() on the shared library (e.g. users of the LXC
  Python bindings)
- LXD as it needs to know the absolute path to its own executable based on
  /proc/self/exe etc.

This commit makes the rexecution of liblxc conditional on whether the
LXC_MEMFD_REXEC environment variable is set or not. If it is then liblxc is
unconditionally rexecuted.

The only relevant attack vector exists for lxc-attach which we simply reexecute
unconditionally.

Reported-by: Stéphane Graber <stgraber@ubuntu.com>
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
---
 src/lxc/Makefile.am        |  4 +++-
 src/lxc/rexec.c            |  4 ++--
 src/lxc/rexec.h            | 26 ++++++++++++++++++++++++++
 src/lxc/tools/lxc_attach.c | 18 ++++++++++++++++++
 4 files changed, 49 insertions(+), 3 deletions(-)
 create mode 100644 src/lxc/rexec.h

diff --git a/src/lxc/Makefile.am b/src/lxc/Makefile.am
index e1499a7ebe..ef19df9e08 100644
--- a/src/lxc/Makefile.am
+++ b/src/lxc/Makefile.am
@@ -25,6 +25,7 @@ noinst_HEADERS = api_extensions.h \
 		 monitor.h \
 		 namespace.h \
 		 raw_syscalls.h \
+		 rexec.h \
 		 start.h \
 		 state.h \
 		 storage/btrfs.h \
@@ -180,7 +181,7 @@ liblxc_la_SOURCES += ../include/strlcat.c ../include/strlcat.h
 endif
 
 if ENFORCE_MEMFD_REXEC
-liblxc_la_SOURCES += rexec.c
+liblxc_la_SOURCES += rexec.c rexec.h
 endif
 
 AM_CFLAGS = -DLXCROOTFSMOUNT=\"$(LXCROOTFSMOUNT)\" \
@@ -307,6 +308,7 @@ LDADD = liblxc.la \
 
 if ENABLE_TOOLS
 lxc_attach_SOURCES = tools/lxc_attach.c \
+		     rexec.c rexec.h \
 		     tools/arguments.c tools/arguments.h
 lxc_autostart_SOURCES = tools/lxc_autostart.c \
 			tools/arguments.c tools/arguments.h
diff --git a/src/lxc/rexec.c b/src/lxc/rexec.c
index 3ce499b1e2..024728d855 100644
--- a/src/lxc/rexec.c
+++ b/src/lxc/rexec.c
@@ -142,7 +142,7 @@ static void lxc_rexec_as_memfd(char **argv, char **envp, const char *memfd_name)
 	errno = saved_errno;
 }
 
-static int lxc_rexec(const char *memfd_name)
+int lxc_rexec(const char *memfd_name)
 {
 	int ret;
 	char **argv = NULL, **envp = NULL;
@@ -179,7 +179,7 @@ static int lxc_rexec(const char *memfd_name)
  */
 __attribute__((constructor)) static void liblxc_rexec(void)
 {
-	if (lxc_rexec("liblxc")) {
+	if (getenv("LXC_MEMFD_REXEC") && lxc_rexec("liblxc")) {
 		fprintf(stderr, "Failed to re-execute liblxc via memory file descriptor\n");
 		_exit(EXIT_FAILURE);
 	}
diff --git a/src/lxc/rexec.h b/src/lxc/rexec.h
new file mode 100644
index 0000000000..088ded932d
--- /dev/null
+++ b/src/lxc/rexec.h
@@ -0,0 +1,26 @@
+/* liblxcapi
+ *
+ * Copyright © 2019 Christian Brauner <christian.brauner@ubuntu.com>.
+ * Copyright © 2019 Canonical Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __LXC_REXEC_H
+#define __LXC_REXEC_H
+
+extern int lxc_rexec(const char *memfd_name);
+
+#endif /* __LXC_REXEC_H */
diff --git a/src/lxc/tools/lxc_attach.c b/src/lxc/tools/lxc_attach.c
index 3de0d7747f..d10b6ecc23 100644
--- a/src/lxc/tools/lxc_attach.c
+++ b/src/lxc/tools/lxc_attach.c
@@ -44,10 +44,28 @@
 #include "config.h"
 #include "confile.h"
 #include "log.h"
+#include "rexec.h"
 #include "utils.h"
 
 lxc_log_define(lxc_attach, lxc);
 
+/**
+ * This function will copy any binary that calls liblxc into a memory file and
+ * will use the memfd to rexecute the binary. This is done to prevent attacks
+ * through the /proc/self/exe symlink to corrupt the host binary when host and
+ * container are in the same user namespace or have set up an identity id
+ * mapping: CVE-2019-5736.
+ */
+#ifdef ENFORCE_MEMFD_REXEC
+__attribute__((constructor)) static void lxc_attach_rexec(void)
+{
+	if (!getenv("LXC_MEMFD_REXEC") && lxc_rexec("lxc-attach")) {
+		fprintf(stderr, "Failed to re-execute lxc-attach via memory file descriptor\n");
+		_exit(EXIT_FAILURE);
+	}
+}
+#endif
+
 static int my_parser(struct lxc_arguments *args, int c, char *arg);
 static int add_to_simple_array(char ***array, ssize_t *capacity, char *value);
 static bool stdfd_is_pty(void);