mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-27 12:28:27 +00:00
Merge pull request #2698 from brauner/2018-10-17/config_parsing
parse: protect against config updates during parse
This commit is contained in:
commit
b37348d8f2
@ -3344,9 +3344,8 @@ void remount_all_slave(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __LXC_SENDFILE_MAX 0x7ffff000 /* maximum number of bytes sendfile can handle */
|
|
||||||
again:
|
again:
|
||||||
copied = sendfile(memfd, mntinfo_fd, NULL, __LXC_SENDFILE_MAX);
|
copied = lxc_sendfile_nointr(memfd, mntinfo_fd, NULL, LXC_SENDFILE_MAX);
|
||||||
if (copied < 0) {
|
if (copied < 0) {
|
||||||
if (errno == EINTR)
|
if (errno == EINTR)
|
||||||
goto again;
|
goto again;
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <linux/magic.h>
|
#include <linux/magic.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/sendfile.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
@ -313,3 +314,19 @@ FILE *fopen_cloexec(const char *path, const char *mode)
|
|||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t lxc_sendfile_nointr(int out_fd, int in_fd, off_t *offset, size_t count)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
again:
|
||||||
|
ret = sendfile(out_fd, in_fd, offset, count);
|
||||||
|
if (ret < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
goto again;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@ -53,5 +53,7 @@ extern bool has_fs_type(const char *path, fs_type_magic magic_val);
|
|||||||
extern bool fhas_fs_type(int fd, fs_type_magic magic_val);
|
extern bool fhas_fs_type(int fd, fs_type_magic magic_val);
|
||||||
extern bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val);
|
extern bool is_fs_type(const struct statfs *fs, fs_type_magic magic_val);
|
||||||
extern FILE *fopen_cloexec(const char *path, const char *mode);
|
extern FILE *fopen_cloexec(const char *path, const char *mode);
|
||||||
|
extern ssize_t lxc_sendfile_nointr(int out_fd, int in_fd, off_t *offset,
|
||||||
|
size_t count);
|
||||||
|
|
||||||
#endif /* __LXC_FILE_UTILS_H */
|
#endif /* __LXC_FILE_UTILS_H */
|
||||||
|
@ -389,4 +389,7 @@ enum {
|
|||||||
#define STRLITERALLEN(x) (sizeof(""x"") - 1)
|
#define STRLITERALLEN(x) (sizeof(""x"") - 1)
|
||||||
#define STRARRAYLEN(x) (sizeof(x) - 1)
|
#define STRARRAYLEN(x) (sizeof(x) - 1)
|
||||||
|
|
||||||
|
/* Maximum number of bytes sendfile() is able to send in one go. */
|
||||||
|
#define LXC_SENDFILE_MAX 0x7ffff000
|
||||||
|
|
||||||
#endif /* __LXC_MACRO_H */
|
#endif /* __LXC_MACRO_H */
|
||||||
|
@ -30,10 +30,14 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
|
#include <sys/sendfile.h>
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "file_utils.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "macro.h"
|
||||||
#include "parse.h"
|
#include "parse.h"
|
||||||
|
#include "syscall_wrappers.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
lxc_log_define(parse, lxc);
|
lxc_log_define(parse, lxc);
|
||||||
@ -67,35 +71,67 @@ int lxc_strmunmap(void *addr, size_t length)
|
|||||||
|
|
||||||
int lxc_file_for_each_line_mmap(const char *file, lxc_file_cb callback, void *data)
|
int lxc_file_for_each_line_mmap(const char *file, lxc_file_cb callback, void *data)
|
||||||
{
|
{
|
||||||
int fd, saved_errno;
|
int saved_errno;
|
||||||
char *buf, *line;
|
ssize_t ret, bytes_sent;
|
||||||
struct stat st;
|
char *line;
|
||||||
int ret = 0;
|
int fd = -1, memfd = -1;
|
||||||
|
char *buf = NULL;
|
||||||
|
|
||||||
|
memfd = memfd_create(".lxc_config_file", MFD_CLOEXEC);
|
||||||
|
if (memfd < 0) {
|
||||||
|
char template[] = P_tmpdir "/.lxc_config_file_XXXXXX";
|
||||||
|
|
||||||
|
if (errno != ENOSYS) {
|
||||||
|
SYSERROR("Failed to create memory file");
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("Failed to create in-memory file. Falling back to "
|
||||||
|
"temporary file");
|
||||||
|
memfd = lxc_make_tmpfile(template, true);
|
||||||
|
if (memfd < 0) {
|
||||||
|
SYSERROR("Failed to create temporary file \"%s\"", template);
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fd = open(file, O_RDONLY | O_CLOEXEC);
|
fd = open(file, O_RDONLY | O_CLOEXEC);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
SYSERROR("Failed to open config file \"%s\"", file);
|
SYSERROR("Failed to open file \"%s\"", file);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = fstat(fd, &st);
|
|
||||||
if (ret < 0) {
|
|
||||||
SYSERROR("Failed to stat config file \"%s\"", file);
|
|
||||||
goto on_error_fstat;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 0;
|
/* sendfile() handles up to 2GB. No config file should be that big. */
|
||||||
if (st.st_size == 0)
|
bytes_sent = lxc_sendfile_nointr(memfd, fd, NULL, LXC_SENDFILE_MAX);
|
||||||
goto on_error_fstat;
|
if (bytes_sent < 0) {
|
||||||
|
SYSERROR("Failed to sendfile \"%s\"", file);
|
||||||
ret = -1;
|
|
||||||
buf = lxc_strmmap(NULL, st.st_size, PROT_READ | PROT_WRITE,
|
|
||||||
MAP_PRIVATE | MAP_POPULATE, fd, 0);
|
|
||||||
if (buf == MAP_FAILED) {
|
|
||||||
SYSERROR("Failed to map config file \"%s\"", file);
|
|
||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = lxc_write_nointr(memfd, "\0", 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
SYSERROR("Failed to append zero byte");
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
bytes_sent++;
|
||||||
|
|
||||||
|
ret = lseek(memfd, 0, SEEK_SET);
|
||||||
|
if (ret < 0) {
|
||||||
|
SYSERROR("Failed to lseek");
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = -1;
|
||||||
|
buf = mmap(NULL, bytes_sent, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_SHARED | MAP_POPULATE, memfd, 0);
|
||||||
|
if (buf == MAP_FAILED) {
|
||||||
|
buf = NULL;
|
||||||
|
SYSERROR("Failed to mmap");
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
lxc_iterate_parts(line, buf, "\n\0") {
|
lxc_iterate_parts(line, buf, "\n\0") {
|
||||||
ret = callback(line, data);
|
ret = callback(line, data);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
@ -104,22 +140,22 @@ int lxc_file_for_each_line_mmap(const char *file, lxc_file_cb callback, void *da
|
|||||||
*/
|
*/
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
ERROR("Failed to parse config file \"%s\" at "
|
ERROR("Failed to parse config file \"%s\" at "
|
||||||
"line \"%s\"",
|
"line \"%s\"", file, line);
|
||||||
file, line);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
on_error:
|
on_error:
|
||||||
if (lxc_strmunmap(buf, st.st_size) < 0) {
|
saved_errno = errno;
|
||||||
SYSERROR("Failed to unmap config file \"%s\"", file);
|
if (fd >= 0)
|
||||||
|
close(fd);
|
||||||
|
if (memfd >= 0)
|
||||||
|
close(memfd);
|
||||||
|
if (buf && munmap(buf, bytes_sent)) {
|
||||||
|
SYSERROR("Failed to unmap");
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
on_error_fstat:
|
|
||||||
saved_errno = errno;
|
|
||||||
close(fd);
|
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user