From 073f0ba33ad72474de7e7465c5e10a94fda32611 Mon Sep 17 00:00:00 2001 From: zhangxingrong Date: Thu, 15 Aug 2024 13:57:30 +0800 Subject: [PATCH] add some upstream patchs --- ...x-ABBA-deadlock-between-read-refresh.patch | 107 ++++++++++++++++ ...atible-integer-to-pointer-conversion.patch | 41 ++++++ ...oadavg-make-cleanup-of-start_loadavg.patch | 118 ++++++++++++++++++ ...ss-a-correct-argument-to-lxcfs_debug.patch | 33 +++++ lxcfs.spec | 13 +- 5 files changed, 311 insertions(+), 1 deletion(-) create mode 100644 0017-proc_loadavg-fix-ABBA-deadlock-between-read-refresh.patch create mode 100644 0018-proc_loadavg-Fix-incompatible-integer-to-pointer-conversion.patch create mode 100644 0019-loadavg-make-cleanup-of-start_loadavg.patch create mode 100644 0020-cpuview-pass-a-correct-argument-to-lxcfs_debug.patch diff --git a/0017-proc_loadavg-fix-ABBA-deadlock-between-read-refresh.patch b/0017-proc_loadavg-fix-ABBA-deadlock-between-read-refresh.patch new file mode 100644 index 0000000..f979278 --- /dev/null +++ b/0017-proc_loadavg-fix-ABBA-deadlock-between-read-refresh.patch @@ -0,0 +1,107 @@ +From 362a5d52bf67ff58e07f970abd0e642b3bf8279b Mon Sep 17 00:00:00 2001 +From: Alexander Mikhalitsyn +Date: Wed, 9 Aug 2023 18:39:46 +0200 +Subject: [PATCH] proc_loadavg: fix ABBA deadlock between read/refresh + +Idea of this fix is to always take nested locks in +the same order. + +At the same time, we adding an extra check to insert_node() +that prevents adding a new load_node with the same cgroup +(->cg field) value. This is theoretically possible because +we don't hold .rilock/.lock when we call insert_node(). + +It looks like we have this issue from the initial +implementation of loadavg virtualization and it's hardly +reproducible that's why we weren't able to notice it. + +Fixes: #605 +Signed-off-by: Alexander Mikhalitsyn +--- + src/proc_loadavg.c | 37 +++++++++++++++++++++++++++++++++++-- + 1 file changed, 35 insertions(+), 2 deletions(-) + +diff --git a/src/proc_loadavg.c b/src/proc_loadavg.c +index b7411c47..88cf2fbd 100644 +--- a/src/proc_loadavg.c ++++ b/src/proc_loadavg.c +@@ -73,6 +73,11 @@ struct load_node { + }; + + struct load_head { ++ /* ++ * To prevent ABBA deadlocks, let's always take this locks in ++ * the order as they specified in this structure. ++ */ ++ + /* + * The lock is about insert load_node and refresh load_node.To the first + * load_node of each hash bucket, insert and refresh in this hash bucket is +@@ -108,8 +113,8 @@ static struct load_node *locate_node(char *cg, int locate) + struct load_node *f = NULL; + int i = 0; + +- pthread_rwlock_rdlock(&load_hash[locate].rilock); + pthread_rwlock_rdlock(&load_hash[locate].rdlock); ++ pthread_rwlock_rdlock(&load_hash[locate].rilock); + if (load_hash[locate].next == NULL) { + pthread_rwlock_unlock(&load_hash[locate].rilock); + return f; +@@ -121,11 +126,37 @@ static struct load_node *locate_node(char *cg, int locate) + return f; + } + ++/* ++ * Inserts a new load_node into the load_hash table, ++ * if an appropriate node exists then just free (*n) and ++ * rewrite (n) value to an existing load_node pointer. ++ * ++ * We should enter this function without any locks held. ++ * This function leaves &load_hash[hash].rdlock taken. ++ */ + static void insert_node(struct load_node **n, int locate) + { + struct load_node *f; + + pthread_mutex_lock(&load_hash[locate].lock); ++ ++ /* ++ * We have to recheck if the node we are looking for ++ * has appeared in the hash table. In this case we just free ++ * newly created load_node and give an existing load_node to use. ++ */ ++ f = locate_node((*n)->cg, locate); ++ if (f) { ++ free_disarm((*n)->cg); ++ free_disarm((*n)); ++ *n = f; ++ ++ pthread_mutex_unlock(&load_hash[locate].lock); ++ return; ++ } ++ ++ /* &load_hash[hash].rdlock is taken for read at this point */ ++ + pthread_rwlock_wrlock(&load_hash[locate].rilock); + f = load_hash[locate].next; + load_hash[locate].next = *n; +@@ -219,7 +250,9 @@ int proc_loadavg_read(char *buf, size_t size, off_t offset, + n->total_pid = 1; + n->last_pid = initpid; + n->cfd = cfd; ++ pthread_rwlock_unlock(&load_hash[hash].rdlock); + insert_node(&n, hash); ++ /* &load_hash[hash].rdlock is taken for reading at this point */ + } + a = n->avenrun[0] + (FIXED_1 / 200); + b = n->avenrun[1] + (FIXED_1 / 200); +@@ -567,8 +600,8 @@ static void load_free(void) + + for (int i = 0; i < LOAD_SIZE; i++) { + pthread_mutex_lock(&load_hash[i].lock); +- pthread_rwlock_wrlock(&load_hash[i].rilock); + pthread_rwlock_wrlock(&load_hash[i].rdlock); ++ pthread_rwlock_wrlock(&load_hash[i].rilock); + if (load_hash[i].next == NULL) { + pthread_mutex_unlock(&load_hash[i].lock); + pthread_mutex_destroy(&load_hash[i].lock); diff --git a/0018-proc_loadavg-Fix-incompatible-integer-to-pointer-conversion.patch b/0018-proc_loadavg-Fix-incompatible-integer-to-pointer-conversion.patch new file mode 100644 index 0000000..63b0f4e --- /dev/null +++ b/0018-proc_loadavg-Fix-incompatible-integer-to-pointer-conversion.patch @@ -0,0 +1,41 @@ +From 1ce7d26de2f97acf4b979d7993d83ddfe53cc8ee Mon Sep 17 00:00:00 2001 +From: Brahmajit Das +Date: Tue, 5 Sep 2023 04:15:06 +0000 +Subject: [PATCH] proc_loadavg.c: Fix incompatible integer to pointer + conversion + +Newer compiler like Clang 16 and GCC 14 have certain error enabled by +default, namely -Werror=incompatible-function-pointer-types. Which +resutls in build error such as: + +proc_loadavg.c:606:10: error: incompatible integer to pointer conversion returning int from a function with result type pthread_t + +My patch supresses the error for now, but a proper fix would be better. +Fist discovered on Gentoo linux (bug #894348). + +Bug: https://bugs.gentoo.org/894348 +Closes: https://github.com/lxc/lxcfs/issues/561 +Signed-off-by: Brahmajit Das +--- + src/proc_loadavg.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/proc_loadavg.c b/src/proc_loadavg.c +index 88cf2fbd..0be04f47 100644 +--- a/src/proc_loadavg.c ++++ b/src/proc_loadavg.c +@@ -636,12 +636,12 @@ pthread_t load_daemon(int load_use) + + ret = init_load(); + if (ret == -1) +- return log_error(0, "Initialize hash_table fails in load_daemon!"); ++ return (pthread_t)log_error(0, "Initialize hash_table fails in load_daemon!"); + + ret = pthread_create(&pid, NULL, load_begin, NULL); + if (ret != 0) { + load_free(); +- return log_error(0, "Create pthread fails in load_daemon!"); ++ return (pthread_t)log_error(0, "Create pthread fails in load_daemon!"); + } + + /* use loadavg, here loadavg = 1*/ diff --git a/0019-loadavg-make-cleanup-of-start_loadavg.patch b/0019-loadavg-make-cleanup-of-start_loadavg.patch new file mode 100644 index 0000000..292e656 --- /dev/null +++ b/0019-loadavg-make-cleanup-of-start_loadavg.patch @@ -0,0 +1,118 @@ +From e0533550b2c26c6d3dc86394f4eac99082587c9c Mon Sep 17 00:00:00 2001 +From: Alexander Mikhalitsyn +Date: Fri, 29 Sep 2023 16:34:05 +0200 +Subject: [PATCH] loadavg: make cleanup of start_loadavg + +Cleanup start_loadavg code: +- add a new external symbol load_daemon_v2 with the pthread_create-like signature +- make hacky casts of pthread_t to int (and reverse) unnecessary for new API users + +Related to: #610 + +Signed-off-by: Alexander Mikhalitsyn +--- + src/lxcfs.c | 24 ++++++++++++++++++++++++ + src/proc_loadavg.c | 24 ++++++++++++++++++++++-- + src/proc_loadavg.h | 1 + + 3 files changed, 47 insertions(+), 2 deletions(-) + +diff --git a/src/lxcfs.c b/src/lxcfs.c +index ef35460d..44fa4f50 100644 +--- a/src/lxcfs.c ++++ b/src/lxcfs.c +@@ -89,13 +89,37 @@ static int start_loadavg(void) + { + char *error; + pthread_t (*__load_daemon)(int); ++ int (*__load_daemon_v2)(pthread_t *, int); + ++ /* try a new load_daemon_v2() API */ ++ dlerror(); ++ __load_daemon_v2 = (int (*)(pthread_t *, int))dlsym(dlopen_handle, "load_daemon_v2"); ++ error = dlerror(); ++ if (error) ++ /* try with an old symbol name */ ++ goto old_api; ++ ++ lxcfs_debug("start_loadavg: using load_daemon_v2"); ++ ++ if (__load_daemon_v2(&loadavg_pid, 1)) { ++ /* we have to NULLify loadavg_pid as in case of error it's contents are undefined */ ++ loadavg_pid = 0; ++ return log_error(-1, "Failed to start loadavg daemon"); ++ } ++ ++ /* we are done */ ++ return 0; ++ ++old_api: ++ /* go with an old load_daemon() API */ + dlerror(); + __load_daemon = (pthread_t(*)(int))dlsym(dlopen_handle, "load_daemon"); + error = dlerror(); + if (error) + return log_error(-1, "%s - Failed to start loadavg daemon", error); + ++ lxcfs_debug("start_loadavg: using load_daemon"); ++ + loadavg_pid = __load_daemon(1); + if (!loadavg_pid) + return -1; +diff --git a/src/proc_loadavg.c b/src/proc_loadavg.c +index 0be04f47..e8456c5a 100644 +--- a/src/proc_loadavg.c ++++ b/src/proc_loadavg.c +@@ -628,7 +628,7 @@ static void load_free(void) + } + } + +-/* Return a positive number on success, return 0 on failure.*/ ++/* Return a positive number on success, return 0 on failure. */ + pthread_t load_daemon(int load_use) + { + int ret; +@@ -644,11 +644,31 @@ pthread_t load_daemon(int load_use) + return (pthread_t)log_error(0, "Create pthread fails in load_daemon!"); + } + +- /* use loadavg, here loadavg = 1*/ ++ /* use loadavg, here loadavg = 1 */ + loadavg = load_use; + return pid; + } + ++/* Return 0 on success, return -1 on failure. */ ++int load_daemon_v2(pthread_t *thread, int load_use) ++{ ++ int ret; ++ ++ ret = init_load(); ++ if (ret == -1) ++ return log_error(-1, "Initialize hash_table fails in load_daemon!"); ++ ++ ret = pthread_create(thread, NULL, load_begin, NULL); ++ if (ret != 0) { ++ load_free(); ++ return log_error(-1, "%s - Create pthread fails in load_daemon!", strerror(ret)); ++ } ++ ++ /* use loadavg, here loadavg = 1 */ ++ loadavg = load_use; ++ return 0; ++} ++ + /* Returns 0 on success. */ + int stop_load_daemon(pthread_t pid) + { +diff --git a/src/proc_loadavg.h b/src/proc_loadavg.h +index e6ae2ded..03d2ca6d 100644 +--- a/src/proc_loadavg.h ++++ b/src/proc_loadavg.h +@@ -16,6 +16,7 @@ + #include "macro.h" + + __visible extern pthread_t load_daemon(int load_use); ++__visible extern int load_daemon_v2(pthread_t *thread, int load_use); + __visible extern int stop_load_daemon(pthread_t pid); + + extern int proc_loadavg_read(char *buf, size_t size, off_t offset, struct fuse_file_info *fi); diff --git a/0020-cpuview-pass-a-correct-argument-to-lxcfs_debug.patch b/0020-cpuview-pass-a-correct-argument-to-lxcfs_debug.patch new file mode 100644 index 0000000..2feccd1 --- /dev/null +++ b/0020-cpuview-pass-a-correct-argument-to-lxcfs_debug.patch @@ -0,0 +1,33 @@ +From a019277c7f325dd20678d23b8210156ef4bd2318 Mon Sep 17 00:00:00 2001 +From: Alexander Mikhalitsyn +Date: Fri, 29 Sep 2023 17:28:46 +0200 +Subject: [PATCH] cpuview: pass a correct argument to lxcfs_debug + +struct cg_proc_stat *cur; +... +lxcfs_debug("Removing stat node for %s\n", cur); + +should be: + +lxcfs_debug("Removing stat node for %s\n", cur->cg); + +Only reproducible when DEBUG macro is defined. + +Signed-off-by: Alexander Mikhalitsyn +--- + src/proc_cpuview.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/proc_cpuview.c b/src/proc_cpuview.c +index 14afdd0b..0063fd58 100644 +--- a/src/proc_cpuview.c ++++ b/src/proc_cpuview.c +@@ -265,7 +265,7 @@ static struct cg_proc_stat *prune_proc_stat_list(struct cg_proc_stat *node) + first = node->next; + + node = node->next; +- lxcfs_debug("Removing stat node for %s\n", cur); ++ lxcfs_debug("Removing stat node for %s\n", cur->cg); + + free_proc_stat_node(cur); + } else { diff --git a/lxcfs.spec b/lxcfs.spec index 884b2cb..f8d0015 100644 --- a/lxcfs.spec +++ b/lxcfs.spec @@ -4,7 +4,7 @@ #Basic Information Name: lxcfs Version: 5.0.4 -Release: 2 +Release: 3 Summary: FUSE filesystem for LXC License: LGPL 2.1+ URL: http://linuxcontainers.org @@ -26,6 +26,11 @@ Patch9013: 0013-enable-cfs-option-to-show-correct-proc-cpuinfo-view.patch Patch9014: 0014-fix-pidfd_open-pidfd_send_signal-function-compilatio.patch Patch9015: 0015-adapt-meson-build-install.patch Patch9016: 0016-typofix-fix-incorrect-printing-in-lxcfs-help-interfa.patch +Patch9017: 0017-proc_loadavg-fix-ABBA-deadlock-between-read-refresh.patch +Patch9018: 0018-proc_loadavg-Fix-incompatible-integer-to-pointer-conversion.patch +Patch9019: 0019-loadavg-make-cleanup-of-start_loadavg.patch +patch9020: 0020-cpuview-pass-a-correct-argument-to-lxcfs_debug.patch + #Dependency BuildRequires: meson python3-jinja2 help2man @@ -82,6 +87,12 @@ fi %{_unitdir}/* %changelog +* Thu Aug 15 2024 zhangxingrong - 5.0.4-3 +- proc_loadavg: fix ABBA deadlock between read/refresh +- proc_loadavg.c: Fix incompatible integer to pointer conversion +- loadavg: make cleanup of start_loadavg +- cpuview: pass a correct argument to lxcfs_debug + * Fri Dec 15 2023 yangjiaqi - 5.0.4-2 - Type:bugfix - CVE:NA -- Gitee