From ce9638164a63d1385cee48b45d868dbd09f6e029 Mon Sep 17 00:00:00 2001 From: Jones Syue Date: Wed, 8 Jan 2025 17:14:08 +0800 Subject: [PATCH 1/2] [linux] fix: memory-mapped file, stat: No such file or directory In old linux kernel (e.g. linux-2.6) which does not have this feature: Commit 6b4e306aa3dc ("ns: proc files for namespace naming policy."), means this path "/proc/self/ns" is not existed. Since lsof-4.96.0 with Commit dbad15094a98 (" [linux] obtain correct information of memory-mapped file."), compare_mntns() would misunderstand it is in a different mount namespace if "/proc/self/ns" is not existed, returns -1, go through map_files lookup, and finally lead to lsof gets failed with error message "stat: No such file or directory". If "/proc/self/ns" or its underlying path is not existed, compare_mntns() returns 0 instead of -1, in order to go through stat_directly as old days. Signed-off-by: Jones Syue --- lib/dialects/linux/dproc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/dialects/linux/dproc.c b/lib/dialects/linux/dproc.c index 3a7a1204..60624a96 100644 --- a/lib/dialects/linux/dproc.c +++ b/lib/dialects/linux/dproc.c @@ -1370,14 +1370,14 @@ static int compare_mntns(int pid) /* pid of the target process */ int ret; if (stat("/proc/self/ns/mnt", &sb_self)) - return -1; + return 0; ret = snprintf(nspath, sizeof(nspath), "/proc/%d/ns/mnt", pid); if (ret >= sizeof(nspath) || ret <= 0) - return -1; + return 0; if (stat(nspath, &sb_target)) - return -1; + return 0; if (sb_self.st_ino != sb_target.st_ino) return -1; From 904534a26f52eee173b8de055ddadd8bfdd84268 Mon Sep 17 00:00:00 2001 From: Jones Syue Date: Thu, 9 Jan 2025 17:00:49 +0800 Subject: [PATCH 2/2] Add comments: logic behind comparison compare_mntns() Add comments: Compare the inode number of mount namespace, to see if target process is in a different mount namespace from lsof process: return 0 (false) means mount namespace is the same, and return 1 (true) means mount namespace is different. Note that legacy linux kernel (e.g. linux-2.6) might not have this mount namespace path, so makes this case return 0 (false) and acts as old days. Signed-off-by: Jones Syue --- lib/dialects/linux/dproc.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/lib/dialects/linux/dproc.c b/lib/dialects/linux/dproc.c index 60624a96..dbb0e1a2 100644 --- a/lib/dialects/linux/dproc.c +++ b/lib/dialects/linux/dproc.c @@ -1361,7 +1361,17 @@ static int process_id(struct lsof_context *ctx, /* context */ return (0); } -/* compare mount namespace of this lsof process and the target process */ +/* + * compare_mntns() - compare mount namespace of this lsof process and the + * target process + * + * Note: mount namespace path might not be found with legacy linux kernel (e.g. + * linux-2.6) which does not have path "/proc/self/ns" or "/proc/${pid}/ns", + * see Commit 6b4e306aa3dc ("ns: proc files for namespace naming policy.") + * + * return: 0 == mount namespace is the same, or path is not found. + * 1 == mount namespace is different. + */ static int compare_mntns(int pid) /* pid of the target process */ { @@ -1369,9 +1379,17 @@ static int compare_mntns(int pid) /* pid of the target process */ struct stat sb_self, sb_target; int ret; + /* + * Get mount namespace of this lsof process, early return if path is not + * found. + */ if (stat("/proc/self/ns/mnt", &sb_self)) return 0; + /* + * Get mount namespace of the target process, early return if path is not + * found. + */ ret = snprintf(nspath, sizeof(nspath), "/proc/%d/ns/mnt", pid); if (ret >= sizeof(nspath) || ret <= 0) return 0; @@ -1379,9 +1397,16 @@ static int compare_mntns(int pid) /* pid of the target process */ if (stat(nspath, &sb_target)) return 0; + /* + * Compare the inode number of mount namespace, to see if target process + * is in a different mount namespace from lsof process. + */ if (sb_self.st_ino != sb_target.st_ino) - return -1; + return 1; + /* + * mount namespace is the same. + */ return 0; }