]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/rexec.c
0589b4a781e1e56e16e4febd6c81f93f035db1fe
3 * Copyright © 2019 Christian Brauner <christian.brauner@ubuntu.com>.
4 * Copyright © 2019 Canonical Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this library; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
31 #include "file_utils.h"
33 #include "memory_utils.h"
34 #include "raw_syscalls.h"
35 #include "string_utils.h"
36 #include "syscall_wrappers.h"
39 #include "../include/fexecve.h"
42 #define LXC_MEMFD_REXEC_SEALS \
43 (F_SEAL_SEAL | F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE)
45 static int push_vargs(char *data
, int data_length
, char ***output
)
53 *output
= must_realloc(NULL
, sizeof(**output
));
55 while (cur
< data
+ data_length
) {
57 *output
= must_realloc(*output
, (num
+ 1) * sizeof(**output
));
59 (*output
)[num
- 1] = cur
;
60 cur
+= strlen(cur
) + 1;
62 (*output
)[num
] = NULL
;
66 static int parse_argv(char ***argv
)
68 __do_free
char *cmdline
= NULL
;
72 cmdline
= file_to_buf("/proc/self/cmdline", &cmdline_size
);
76 ret
= push_vargs(cmdline
, cmdline_size
, argv
);
84 static int is_memfd(void)
86 __do_close_prot_errno
int fd
= -EBADF
;
87 int saved_errno
, seals
;
89 fd
= open("/proc/self/exe", O_RDONLY
| O_CLOEXEC
);
91 return -ENOTRECOVERABLE
;
93 seals
= fcntl(fd
, F_GET_SEALS
);
97 return seals
== LXC_MEMFD_REXEC_SEALS
;
100 static void lxc_rexec_as_memfd(char **argv
, char **envp
, const char *memfd_name
)
102 __do_close_prot_errno
int fd
= -EBADF
, memfd
= -EBADF
;
106 memfd
= memfd_create(memfd_name
, MFD_ALLOW_SEALING
| MFD_CLOEXEC
);
110 fd
= open("/proc/self/exe", O_RDONLY
| O_CLOEXEC
);
114 /* sendfile() handles up to 2GB. */
115 bytes_sent
= lxc_sendfile_nointr(memfd
, fd
, NULL
, LXC_SENDFILE_MAX
);
119 if (fcntl(memfd
, F_ADD_SEALS
, LXC_MEMFD_REXEC_SEALS
))
122 fexecve(memfd
, argv
, envp
);
126 * Get cheap access to the environment. This must be declared by the user as
127 * mandated by POSIX. The definition is located in unistd.h.
129 extern char **environ
;
131 int lxc_rexec(const char *memfd_name
)
137 if (ret
< 0 && ret
== -ENOTRECOVERABLE
) {
139 "%s - Failed to determine whether this is a memfd\n",
142 } else if (ret
> 0) {
146 ret
= parse_argv(&argv
);
149 "%s - Failed to parse command line parameters\n",
154 lxc_rexec_as_memfd(argv
, environ
, memfd_name
);
155 fprintf(stderr
, "%s - Failed to rexec as memfd\n", strerror(errno
));
160 * This function will copy any binary that calls liblxc into a memory file and
161 * will use the memfd to rexecute the binary. This is done to prevent attacks
162 * through the /proc/self/exe symlink to corrupt the host binary when host and
163 * container are in the same user namespace or have set up an identity id
164 * mapping: CVE-2019-5736.
166 __attribute__((constructor
)) static void liblxc_rexec(void)
168 if (getenv("LXC_MEMFD_REXEC") && lxc_rexec("liblxc")) {
169 fprintf(stderr
, "Failed to re-execute liblxc via memory file descriptor\n");