lcr/0014-288-use-atomic-write-for-config-secomp-oci_hook-file.patch
jikai 3b4b08f18a sync from upstream
Signed-off-by: jikai <jikai11@huawei.com>
(cherry picked from commit 0a5748543c47e895a44afbc57de2d1ad6f9063d9)
2024-06-11 19:20:37 +08:00

628 lines
17 KiB
Diff

From 713d31dfeb4425cfb40f565436504f4056ebe548 Mon Sep 17 00:00:00 2001
From: jake <jikai11@huawei.com>
Date: Tue, 21 Nov 2023 02:45:37 +0000
Subject: [PATCH 14/22] !288 use atomic write for config, secomp, oci_hook
files * use atomic write for config, secomp, oci_hook files
---
src/conf.c | 2 +-
src/lcrcontainer_extend.c | 150 ++++++++++-----------
src/utils.c | 268 +++++++++++++++++++++++++++++++++++++-
src/utils.h | 6 +-
4 files changed, 343 insertions(+), 83 deletions(-)
diff --git a/src/conf.c b/src/conf.c
index 10214f0..bfbfe1a 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -1241,7 +1241,7 @@ static int trans_one_oci_id_mapping(struct lcr_list *conf, const char *typ, cons
if (nret < 0 || (size_t)nret >= sizeof(subid)) {
return -1;
}
- nret = lcr_util_atomic_write_file(path, subid);
+ nret = lcr_util_flock_append_file(path, subid);
if (nret < 0) {
return -1;
}
diff --git a/src/lcrcontainer_extend.c b/src/lcrcontainer_extend.c
index 321be8c..b3202a7 100644
--- a/src/lcrcontainer_extend.c
+++ b/src/lcrcontainer_extend.c
@@ -346,7 +346,7 @@ out:
return ret;
}
-static int lcr_spec_write_seccomp_line(int fd, const char *seccomp)
+static int lcr_spec_write_seccomp_line(FILE *fp, const char *seccomp)
{
size_t len;
char *line = NULL;
@@ -371,14 +371,17 @@ static int lcr_spec_write_seccomp_line(int fd, const char *seccomp)
ERROR("Sprintf failed");
goto cleanup;
}
+
if ((size_t)nret > len - 1) {
nret = (int)(len - 1);
}
+
line[nret] = '\n';
- if (write(fd, line, len) == -1) {
+ if (fwrite(line, 1, len ,fp) != len) {
SYSERROR("Write file failed");
goto cleanup;
}
+
ret = 0;
cleanup:
free(line);
@@ -389,9 +392,7 @@ static char *lcr_save_seccomp_file(const char *bundle, const char *seccomp_conf)
{
char seccomp[PATH_MAX] = { 0 };
char *real_seccomp = NULL;
- int fd = -1;
int nret;
- ssize_t written_cnt;
nret = snprintf(seccomp, sizeof(seccomp), "%s/seccomp", bundle);
if (nret < 0 || (size_t)nret >= sizeof(seccomp)) {
@@ -404,16 +405,9 @@ static char *lcr_save_seccomp_file(const char *bundle, const char *seccomp_conf)
goto cleanup;
}
- fd = lcr_util_open(real_seccomp, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, CONFIG_FILE_MODE);
- if (fd == -1) {
- SYSERROR("Create file %s failed", real_seccomp);
- goto cleanup;
- }
-
- written_cnt = write(fd, seccomp_conf, strlen(seccomp_conf));
- close(fd);
- if (written_cnt == -1) {
- SYSERROR("write seccomp_conf failed");
+ if (lcr_util_atomic_write_file(real_seccomp, seccomp_conf, strlen(seccomp_conf),
+ CONFIG_FILE_MODE, false) != -1) {
+ ERROR("write seccomp_conf failed");
goto cleanup;
}
return real_seccomp;
@@ -605,34 +599,51 @@ out_free:
return NULL;
}
-
-static int lcr_open_config_file(const char *bundle)
+static FILE *lcr_open_tmp_config_file(const char *bundle, char **config_file, char **tmp_file)
{
char config[PATH_MAX] = { 0 };
- char *real_config = NULL;
int fd = -1;
int nret;
+ FILE *fp = NULL;
nret = snprintf(config, sizeof(config), "%s/config", bundle);
if (nret < 0 || (size_t)nret >= sizeof(config)) {
goto out;
}
- nret = lcr_util_ensure_path(&real_config, config);
+ nret = lcr_util_ensure_path(config_file, config);
if (nret < 0) {
ERROR("Failed to ensure path %s", config);
goto out;
}
- fd = lcr_util_open(real_config, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, CONFIG_FILE_MODE);
+ *tmp_file = lcr_util_get_random_tmp_file(*config_file);
+ if (*tmp_file == NULL) {
+ ERROR("Failed to get random tmp file for %s", *config_file);
+ goto out;
+ }
+
+ fd = lcr_util_open(*tmp_file, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, CONFIG_FILE_MODE);
if (fd == -1) {
- SYSERROR("Create file %s failed", real_config);
- lcr_set_error_message(LCR_ERR_RUNTIME, "Create file %s failed", real_config);
+ SYSERROR("Create file %s failed", *tmp_file);
+ lcr_set_error_message(LCR_ERR_RUNTIME, "Create file %s failed", *tmp_file);
+ goto out;
+ }
+
+ fp = fdopen(fd, "w");
+ if (fp == NULL) {
+ ERROR("FILE open failed");
goto out;
}
+
out:
- free(real_config);
- return fd;
+ if (fp == NULL) {
+ free(*tmp_file);
+ *tmp_file = NULL;
+ free(*config_file);
+ *config_file = NULL;
+ }
+ return fp;
}
// escape_string_encode unzip some escape characters
@@ -698,18 +709,17 @@ static char *escape_string_encode(const char *src)
return dst;
}
-static int lcr_spec_write_config(int fd, const struct lcr_list *lcr_conf)
+static int lcr_spec_write_config(FILE *fp, const struct lcr_list *lcr_conf)
{
- struct lcr_list *it = NULL;
size_t len;
- char *line = NULL;
- char *line_encode = NULL;
int ret = -1;
+ struct lcr_list *it = NULL;
+ char *line_encode = NULL;
+ char *line = NULL;
lcr_list_for_each(it, lcr_conf) {
lcr_config_item_t *item = it->elem;
int nret;
- size_t encode_len;
if (item != NULL) {
if (strlen(item->value) > ((SIZE_MAX - strlen(item->name)) - 4)) {
goto cleanup;
@@ -722,7 +732,6 @@ static int lcr_spec_write_config(int fd, const struct lcr_list *lcr_conf)
}
nret = snprintf(line, len, "%s = %s", item->name, item->value);
-
if (nret < 0 || (size_t)nret >= len) {
ERROR("Sprintf failed");
goto cleanup;
@@ -734,19 +743,21 @@ static int lcr_spec_write_config(int fd, const struct lcr_list *lcr_conf)
goto cleanup;
}
- encode_len = strlen(line_encode);
+ len = strlen(line_encode);
+ line_encode[len] = '\n';
- line_encode[encode_len] = '\n';
- if (write(fd, line_encode, encode_len + 1) == -1) {
+ if (fwrite(line_encode, 1, len + 1, fp) != len + 1) {
SYSERROR("Write file failed");
goto cleanup;
}
+
free(line);
line = NULL;
free(line_encode);
line_encode = NULL;
}
}
+
ret = 0;
cleanup:
free(line);
@@ -804,7 +815,9 @@ bool lcr_save_spec(const char *name, const char *lcrpath, const struct lcr_list
const char *path = lcrpath ? lcrpath : LCRPATH;
char *bundle = NULL;
char *seccomp = NULL;
- int fd = -1;
+ char *config_file = NULL;
+ char *tmp_file = NULL;
+ FILE *fp = NULL;
int nret = 0;
if (name == NULL) {
@@ -829,71 +842,47 @@ bool lcr_save_spec(const char *name, const char *lcrpath, const struct lcr_list
}
}
- fd = lcr_open_config_file(bundle);
- if (fd == -1) {
+ fp = lcr_open_tmp_config_file(bundle, &config_file, &tmp_file);
+ if (fp == NULL) {
goto out_free;
}
- if (lcr_spec_write_config(fd, lcr_conf)) {
+ if (lcr_spec_write_config(fp, lcr_conf)) {
goto out_free;
}
if (seccomp_conf != NULL) {
- nret = lcr_spec_write_seccomp_line(fd, seccomp);
+ nret = lcr_spec_write_seccomp_line(fp, seccomp);
if (nret) {
goto out_free;
}
}
- bret = true;
+ fclose(fp);
+ fp = NULL;
-out_free:
- free(bundle);
- free(seccomp);
- if (fd != -1) {
- close(fd);
- }
-
- return bret;
-}
-
-static int lcr_write_file(const char *path, const char *data, size_t len)
-{
- char *real_path = NULL;
- int fd = -1;
- int ret = -1;
-
- if (path == NULL || strlen(path) == 0 || data == NULL || len == 0) {
- return -1;
- }
-
- if (lcr_util_ensure_path(&real_path, path) < 0) {
- ERROR("Failed to ensure path %s", path);
+ nret = rename(tmp_file, config_file);
+ if (nret != 0) {
+ ERROR("Failed to rename old file %s to target %s", tmp_file, config_file);
goto out_free;
}
- fd = lcr_util_open(real_path, O_CREAT | O_TRUNC | O_CLOEXEC | O_WRONLY, CONFIG_FILE_MODE);
- if (fd == -1) {
- ERROR("Create file %s failed", real_path);
- lcr_set_error_message(LCR_ERR_RUNTIME, "Create file %s failed", real_path);
- goto out_free;
- }
-
- if (write(fd, data, len) == -1) {
- SYSERROR("write data to %s failed", real_path);
- goto out_free;
- }
-
- ret = 0;
+ bret = true;
out_free:
- if (fd != -1) {
- close(fd);
+ if (fp != NULL) {
+ fclose(fp);
}
- free(real_path);
- return ret;
-}
+ if (!bret && unlink(tmp_file) != 0 && errno != ENOENT) {
+ SYSERROR("Failed to remove temp file:%s", tmp_file);
+ }
+ free(config_file);
+ free(tmp_file);
+ free(seccomp);
+ free(bundle);
+ return bret;
+}
static bool lcr_write_ocihooks(const char *path, const oci_runtime_spec_hooks *hooks)
{
@@ -907,8 +896,9 @@ static bool lcr_write_ocihooks(const char *path, const oci_runtime_spec_hooks *h
goto out_free;
}
- if (lcr_write_file(path, json_hooks, strlen(json_hooks)) == -1) {
- SYSERROR("write json hooks failed");
+ if (lcr_util_atomic_write_file(path, json_hooks, strlen(json_hooks),
+ CONFIG_FILE_MODE, false) == -1) {
+ ERROR("write json hooks failed");
goto out_free;
}
diff --git a/src/utils.c b/src/utils.c
index df73985..68e9bc4 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -1248,7 +1248,7 @@ out:
return ret;
}
-int lcr_util_atomic_write_file(const char *filepath, const char *content)
+int lcr_util_flock_append_file(const char *filepath, const char *content)
{
int fd;
int ret = 0;
@@ -1284,6 +1284,272 @@ out:
return ret;
}
+static char *lcr_util_path_base(const char *path)
+{
+ char *dir = NULL;
+ int len = 0;
+ int i = 0;
+
+ if (path == NULL) {
+ ERROR("invalid NULL param");
+ return NULL;
+ }
+
+ len = (int)strlen(path);
+ if (len == 0) {
+ return lcr_util_strdup_s(".");
+ }
+
+ dir = lcr_util_strdup_s(path);
+
+ // strip last slashes
+ for (i = len - 1; i >= 0; i--) {
+ if (dir[i] != '/') {
+ break;
+ }
+ dir[i] = '\0';
+ }
+
+ len = (int)strlen(dir);
+ if (len == 0) {
+ free(dir);
+ return lcr_util_strdup_s("/");
+ }
+
+ for (i = len - 1; i >= 0; i--) {
+ if (dir[i] == '/') {
+ break;
+ }
+ }
+
+ if (i < 0) {
+ return dir;
+ }
+
+ char *result = lcr_util_strdup_s(&dir[i + 1]);
+ free(dir);
+ return result;
+}
+
+static char *lcr_util_path_dir(const char *path)
+{
+ char *dir = NULL;
+ int len = 0;
+ int i = 0;
+
+ if (path == NULL) {
+ ERROR("invalid NULL param");
+ return NULL;
+ }
+
+ len = (int)strlen(path);
+ if (len == 0) {
+ return lcr_util_strdup_s(".");
+ }
+
+ dir = lcr_util_strdup_s(path);
+
+ for (i = len - 1; i > 0; i--) {
+ if (dir[i] == '/') {
+ dir[i] = 0;
+ break;
+ }
+ }
+
+ if (i == 0 && dir[0] == '/') {
+ free(dir);
+ return lcr_util_strdup_s("/");
+ }
+
+ return dir;
+}
+
+static int lcr_util_generate_random_str(char *id, size_t len)
+{
+ int fd = -1;
+ int num = 0;
+ size_t i;
+ const int m = 256;
+
+ if (id == NULL) {
+ return -1;
+ }
+
+ len = len / 2;
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd == -1) {
+ ERROR("Failed to open /dev/urandom");
+ return -1;
+ }
+ for (i = 0; i < len; i++) {
+ int nret;
+ if (lcr_util_read_nointr(fd, &num, sizeof(int)) < 0) {
+ ERROR("Failed to read urandom value");
+ close(fd);
+ return -1;
+ }
+ unsigned char rs = (unsigned char)(num % m);
+ nret = snprintf((id + i * 2), ((len - i) * 2 + 1), "%02x", (unsigned int)rs);
+ if (nret < 0 || (size_t)nret >= ((len - i) * 2 + 1)) {
+ ERROR("Failed to snprintf random string");
+ close(fd);
+ return -1;
+ }
+ }
+ close(fd);
+ id[i * 2] = '\0';
+ return 0;
+}
+
+static char *lcr_util_path_join(const char *dir, const char *file)
+{
+ int nret = 0;
+ char path[PATH_MAX] = { 0 };
+ char cleaned[PATH_MAX] = { 0 };
+
+ if (dir == NULL || file == NULL) {
+ ERROR("NULL dir or file failed");
+ return NULL;
+ }
+
+ nret = snprintf(path, PATH_MAX, "%s/%s", dir, file);
+ if (nret < 0 || (size_t)nret >= PATH_MAX) {
+ ERROR("dir or file too long failed");
+ return NULL;
+ }
+
+ if (cleanpath(path, cleaned, sizeof(cleaned)) == NULL) {
+ ERROR("Failed to clean path: %s", path);
+ return NULL;
+ }
+
+ return lcr_util_strdup_s(cleaned);
+}
+
+char *lcr_util_get_random_tmp_file(const char *fname)
+{
+#define RANDOM_TMP_PATH 10
+ int nret = 0;
+ char *result = NULL;
+ char *base = NULL;
+ char *dir = NULL;
+ char rpath[PATH_MAX] = { 0x00 };
+ char random_tmp[RANDOM_TMP_PATH + 1] = { 0x00 };
+
+ if (fname == NULL) {
+ ERROR("Invalid NULL param");
+ return NULL;
+ }
+
+ base = lcr_util_path_base(fname);
+ if (base == NULL) {
+ ERROR("Failed to get base of %s", fname);
+ goto out;
+ }
+
+ dir = lcr_util_path_dir(fname);
+ if (dir == NULL) {
+ ERROR("Failed to get dir of %s", fname);
+ goto out;
+ }
+
+ if (lcr_util_generate_random_str(random_tmp, (size_t)RANDOM_TMP_PATH)) {
+ ERROR("Failed to generate random str for random path");
+ goto out;
+ }
+
+ nret = snprintf(rpath, PATH_MAX, ".tmp-%s-%s", base, random_tmp);
+ if (nret < 0 || (size_t)nret >= PATH_MAX) {
+ ERROR("Failed to generate tmp base file");
+ goto out;
+ }
+
+ result = lcr_util_path_join(dir, rpath);
+
+out:
+ free(base);
+ free(dir);
+ return result;
+}
+
+static int do_atomic_write_file(const char *fname, const char *content, size_t content_len, mode_t mode, bool sync)
+{
+ int ret = 0;
+ int dst_fd = -1;
+ ssize_t len = 0;
+
+ dst_fd = lcr_util_open(fname, O_WRONLY | O_CREAT | O_TRUNC, mode);
+ if (dst_fd < 0) {
+ SYSERROR("Creat file: %s, failed", fname);
+ ret = -1;
+ goto free_out;
+ }
+
+ len = lcr_util_write_nointr(dst_fd, content, content_len);
+ if (len < 0 || ((size_t)len) != content_len) {
+ ret = -1;
+ SYSERROR("Write file failed");
+ goto free_out;
+ }
+
+ if (sync && (fdatasync(dst_fd) != 0)) {
+ ret = -1;
+ SYSERROR("Failed to sync data of file:%s", fname);
+ goto free_out;
+ }
+
+free_out:
+ if (dst_fd >= 0) {
+ close(dst_fd);
+ }
+ return ret;
+}
+
+int lcr_util_atomic_write_file(const char *fname, const char *content, size_t content_len, mode_t mode, bool sync)
+{
+ int ret = 0;
+ char *tmp_file = NULL;
+ char rpath[PATH_MAX] = { 0x00 };
+
+ if (fname == NULL) {
+ return -1;
+ }
+ if (content == NULL || content_len == 0) {
+ return 0;
+ }
+
+ if (cleanpath(fname, rpath, sizeof(rpath)) == NULL) {
+ return -1;
+ }
+
+ tmp_file = lcr_util_get_random_tmp_file(fname);
+ if (tmp_file == NULL) {
+ ERROR("Failed to get tmp file for %s", fname);
+ return -1;
+ }
+
+ ret = do_atomic_write_file(tmp_file, content, content_len, mode, sync);
+ if (ret != 0) {
+ ERROR("Failed to write content to tmp file for %s", tmp_file);
+ ret = -1;
+ goto free_out;
+ }
+
+ ret = rename(tmp_file, rpath);
+ if (ret != 0) {
+ ERROR("Failed to rename old file %s to target %s", tmp_file, rpath);
+ ret = -1;
+ goto free_out;
+ }
+
+free_out:
+ if (ret != 0 && unlink(tmp_file) != 0 && errno != ENOENT) {
+ SYSERROR("Failed to remove temp file:%s", tmp_file);
+ }
+ free(tmp_file);
+ return ret;
+}
+
/* swap in oci is memoy+swap, so here we need to get real swap */
int lcr_util_get_real_swap(int64_t memory, int64_t memory_swap, int64_t *swap)
{
diff --git a/src/utils.h b/src/utils.h
index 6a3764b..51e0dea 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -215,7 +215,11 @@ int lcr_util_safe_llong(const char *numstr, long long *converted);
char *lcr_util_strdup_s(const char *src);
int lcr_util_null_stdfds(void);
-int lcr_util_atomic_write_file(const char *filepath, const char *content);
+int lcr_util_flock_append_file(const char *filepath, const char *content);
+
+char *lcr_util_get_random_tmp_file(const char *fname);
+
+int lcr_util_atomic_write_file(const char *fname, const char *content, size_t content_len, mode_t mode, bool sync);
int lcr_util_get_real_swap(int64_t memory, int64_t memory_swap, int64_t *swap);
int lcr_util_trans_cpushare_to_cpuweight(int64_t cpu_share);
--
2.34.1