public inbox for ltp@lists.linux.it
 help / color / mirror / Atom feed
* [LTP] [PATCH v5 0/3] SysV IPC bug reproducer
@ 2024-03-13  9:23 Andrea Cervesato
  2024-03-13  9:23 ` [LTP] [PATCH v5 1/3] Add SAFE_MPROTECT() macro Andrea Cervesato
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Andrea Cervesato @ 2024-03-13  9:23 UTC (permalink / raw)
  To: ltp

From: Andrea Cervesato <andrea.cervesato@suse.com>

This patch series provides a bug reproducer for SysV IPC, which has been
written by Michal Hocko.
It also includes the SAFE_MPROTECT macro, useful for many other tests as well.

Andrea Cervesato (3):
  Add SAFE_MPROTECT() macro
  Print prot flag when SAFE_MMAP() fails
  Add shmat04 SysV IPC bug reproducer

 include/tst_safe_macros.h                     | 70 +++++++++++++-
 runtest/syscalls                              |  1 +
 runtest/syscalls-ipc                          |  1 +
 .../kernel/syscalls/ipc/shmat/.gitignore      |  1 +
 testcases/kernel/syscalls/ipc/shmat/shmat04.c | 92 +++++++++++++++++++
 5 files changed, 163 insertions(+), 2 deletions(-)
 create mode 100644 testcases/kernel/syscalls/ipc/shmat/shmat04.c

-- 
2.35.3


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [LTP] [PATCH v5 1/3] Add SAFE_MPROTECT() macro
  2024-03-13  9:23 [LTP] [PATCH v5 0/3] SysV IPC bug reproducer Andrea Cervesato
@ 2024-03-13  9:23 ` Andrea Cervesato
  2024-03-13  9:56   ` Cyril Hrubis
  2024-03-13  9:59   ` Cyril Hrubis
  2024-03-13  9:23 ` [LTP] [PATCH v5 2/3] Print prot flag when SAFE_MMAP() fails Andrea Cervesato
  2024-03-13  9:23 ` [LTP] [PATCH v5 3/3] Add shmat04 SysV IPC bug reproducer Andrea Cervesato
  2 siblings, 2 replies; 7+ messages in thread
From: Andrea Cervesato @ 2024-03-13  9:23 UTC (permalink / raw)
  To: ltp

From: Andrea Cervesato <andrea.cervesato@suse.com>

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
Moved SAFE_MPROTECT() macro into tst_safe_macros.h

 include/tst_safe_macros.h | 60 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
index 2d497f344..15f914619 100644
--- a/include/tst_safe_macros.h
+++ b/include/tst_safe_macros.h
@@ -6,6 +6,7 @@
 #ifndef TST_SAFE_MACROS_H__
 #define TST_SAFE_MACROS_H__
 
+#include <stdlib.h>
 #include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/time.h>
@@ -268,6 +269,36 @@ int safe_getgroups(const char *file, const int lineno, int size, gid_t list[]);
  * -D_FILE_OFFSET_BITS=64 compile flag
  */
 
+#define PROT_FLAG_STR(f) #f " | "
+
+static void prot_to_str(const int prot, char *buf)
+{
+	char *ptr = buf;
+
+	if (prot == PROT_NONE) {
+		strcpy(buf, "PROT_NONE");
+		return;
+	}
+
+	if (prot & PROT_READ) {
+		strcpy(ptr, PROT_FLAG_STR(PROT_READ));
+		ptr += sizeof(PROT_FLAG_STR(PROT_READ)) - 1;
+	}
+
+	if (prot & PROT_WRITE) {
+		strcpy(ptr, PROT_FLAG_STR(PROT_WRITE));
+		ptr += sizeof(PROT_FLAG_STR(PROT_WRITE)) - 1;
+	}
+
+	if (prot & PROT_EXEC) {
+		strcpy(ptr, PROT_FLAG_STR(PROT_EXEC));
+		ptr += sizeof(PROT_FLAG_STR(PROT_EXEC)) - 1;
+	}
+
+	if (buf != ptr)
+		ptr[-3] = 0;
+}
+
 static inline void *safe_mmap(const char *file, const int lineno,
                               void *addr, size_t length,
                               int prot, int flags, int fd, off_t offset)
@@ -287,6 +318,35 @@ static inline void *safe_mmap(const char *file, const int lineno,
 	safe_mmap(__FILE__, __LINE__, (addr), (length), (prot), \
 	(flags), (fd), (offset))
 
+static inline int safe_mprotect(const char *file, const int lineno,
+	char *addr, size_t len, int prot)
+{
+	int rval;
+	char *prot_buf;
+
+	prot_buf = (char*) safe_malloc(file, lineno, 0, 512);
+	prot_to_str(prot, prot_buf);
+
+	tst_res_(file, lineno, TDEBUG,
+		"mprotect(%p, %ld, %s(%x))", addr, len, prot_buf, prot);
+
+	free(prot_buf);
+
+	rval = mprotect(addr, len, prot);
+
+	if (rval == -1) {
+		tst_brk_(file, lineno, TBROK | TERRNO,
+			"mprotect() failed");
+	} else if (rval) {
+		tst_brk_(file, lineno, TBROK | TERRNO,
+			"Invalid mprotect() return value %d", rval);
+	}
+
+	return rval;
+}
+#define SAFE_MPROTECT(addr, len, prot) \
+	safe_mprotect(__FILE__, __LINE__, (addr), (len), (prot))
+
 static inline int safe_ftruncate(const char *file, const int lineno,
                                  int fd, off_t length)
 {
-- 
2.35.3


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [LTP] [PATCH v5 2/3] Print prot flag when SAFE_MMAP() fails
  2024-03-13  9:23 [LTP] [PATCH v5 0/3] SysV IPC bug reproducer Andrea Cervesato
  2024-03-13  9:23 ` [LTP] [PATCH v5 1/3] Add SAFE_MPROTECT() macro Andrea Cervesato
@ 2024-03-13  9:23 ` Andrea Cervesato
  2024-03-13  9:57   ` Cyril Hrubis
  2024-03-13  9:23 ` [LTP] [PATCH v5 3/3] Add shmat04 SysV IPC bug reproducer Andrea Cervesato
  2 siblings, 1 reply; 7+ messages in thread
From: Andrea Cervesato @ 2024-03-13  9:23 UTC (permalink / raw)
  To: ltp

From: Andrea Cervesato <andrea.cervesato@suse.com>

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
 include/tst_safe_macros.h | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
index 15f914619..63ad46b85 100644
--- a/include/tst_safe_macros.h
+++ b/include/tst_safe_macros.h
@@ -304,12 +304,18 @@ static inline void *safe_mmap(const char *file, const int lineno,
                               int prot, int flags, int fd, off_t offset)
 {
 	void *rval;
+	char *prot_buf;
 
 	rval = mmap(addr, length, prot, flags, fd, offset);
 	if (rval == MAP_FAILED) {
+		prot_buf = (char*) safe_malloc(file, lineno, 0, 512);
+		prot_to_str(prot, prot_buf);
+
 		tst_brk_(file, lineno, TBROK | TERRNO,
-			"mmap(%p,%zu,%d,%d,%d,%ld) failed",
-			addr, length, prot, flags, fd, (long) offset);
+			"mmap(%p,%zu,%s(%x),%d,%d,%ld) failed",
+			addr, length, prot_buf, prot, flags, fd, (long) offset);
+
+		free(prot_buf);
 	}
 
 	return rval;
-- 
2.35.3


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [LTP] [PATCH v5 3/3] Add shmat04 SysV IPC bug reproducer
  2024-03-13  9:23 [LTP] [PATCH v5 0/3] SysV IPC bug reproducer Andrea Cervesato
  2024-03-13  9:23 ` [LTP] [PATCH v5 1/3] Add SAFE_MPROTECT() macro Andrea Cervesato
  2024-03-13  9:23 ` [LTP] [PATCH v5 2/3] Print prot flag when SAFE_MMAP() fails Andrea Cervesato
@ 2024-03-13  9:23 ` Andrea Cervesato
  2 siblings, 0 replies; 7+ messages in thread
From: Andrea Cervesato @ 2024-03-13  9:23 UTC (permalink / raw)
  To: ltp

From: Andrea Cervesato <andrea.cervesato@suse.com>

This is an LTP port of a SysV bug reproducer provided by Michal Hocko.

When debugging issues with a workload using SysV shmem, Michal Hocko has
come up with a reproducer that shows how a series of mprotect()
operations can result in an elevated shm_nattch and thus leak of the
resource.

Signed-off-by: Andrea Cervesato <andrea.cervesato@suse.com>
---
Ensure that GETIPCKEY() will give a free slot given IPC key + 1

 runtest/syscalls                              |  1 +
 runtest/syscalls-ipc                          |  1 +
 .../kernel/syscalls/ipc/shmat/.gitignore      |  1 +
 testcases/kernel/syscalls/ipc/shmat/shmat04.c | 92 +++++++++++++++++++
 4 files changed, 95 insertions(+)
 create mode 100644 testcases/kernel/syscalls/ipc/shmat/shmat04.c

diff --git a/runtest/syscalls b/runtest/syscalls
index fab870ace..4ed2b5602 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1444,6 +1444,7 @@ setxattr03 setxattr03
 shmat01 shmat01
 shmat02 shmat02
 shmat03 shmat03
+shmat04 shmat04
 
 shmctl01 shmctl01
 shmctl02 shmctl02
diff --git a/runtest/syscalls-ipc b/runtest/syscalls-ipc
index df41140a7..9860394de 100644
--- a/runtest/syscalls-ipc
+++ b/runtest/syscalls-ipc
@@ -49,6 +49,7 @@ semop03 semop03
 
 shmat01 shmat01
 shmat02 shmat02
+shmat04 shmat04
 
 shmctl01 shmctl01
 shmctl02 shmctl02
diff --git a/testcases/kernel/syscalls/ipc/shmat/.gitignore b/testcases/kernel/syscalls/ipc/shmat/.gitignore
index 2b972f8f2..5600b2742 100644
--- a/testcases/kernel/syscalls/ipc/shmat/.gitignore
+++ b/testcases/kernel/syscalls/ipc/shmat/.gitignore
@@ -1,3 +1,4 @@
 /shmat01
 /shmat02
 /shmat03
+/shmat04
diff --git a/testcases/kernel/syscalls/ipc/shmat/shmat04.c b/testcases/kernel/syscalls/ipc/shmat/shmat04.c
new file mode 100644
index 000000000..ed03f8260
--- /dev/null
+++ b/testcases/kernel/syscalls/ipc/shmat/shmat04.c
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2024 SUSE LLC
+ * Author: Michal Hocko <mhocko@suse.com>
+ * LTP port: Andrea Cervesato <andrea.cervesato@suse.com>
+ */
+
+/*\
+ * [Description]
+ *
+ * When debugging issues with a workload using SysV shmem, Michal Hocko has
+ * come up with a reproducer that shows how a series of mprotect()
+ * operations can result in an elevated shm_nattch and thus leak of the
+ * resource.
+ *
+ * The problem is caused by wrong assumptions in vma_merge() commit
+ * 714965ca8252 ("mm/mmap: start distinguishing if vma can be removed in
+ * mergeability test"). The shmem vmas have a vma_ops->close callback
+ * that decrements shm_nattch, and we remove the vma without calling it.
+ *
+ * Patch: https://lore.kernel.org/all/20240222215930.14637-2-vbabka@suse.cz/
+ */
+
+#include "tst_test.h"
+#include "tst_safe_sysv_ipc.h"
+#include "libnewipc.h"
+
+static int segment_id = -1;
+static int key_id;
+static int page_size;
+static size_t segment_size;
+
+static void run(void)
+{
+	struct shmid_ds shmid_ds;
+	void *sh_mem;
+
+	segment_id = SAFE_SHMGET(
+		key_id,
+		segment_size,
+		IPC_CREAT | IPC_EXCL | 0600);
+
+	sh_mem = SAFE_SHMAT(segment_id, NULL, 0);
+
+	tst_res(TINFO, "Attached at %p. key: %d - size: %lu",
+		sh_mem, segment_id, segment_size);
+
+	SAFE_SHMCTL(segment_id, IPC_STAT, &shmid_ds);
+
+	tst_res(TINFO, "Number of attaches: %lu", shmid_ds.shm_nattch);
+
+	SAFE_MPROTECT(sh_mem + page_size, page_size, PROT_NONE);
+	SAFE_MPROTECT(sh_mem, 2 * page_size, PROT_WRITE);
+
+	SAFE_SHMCTL(segment_id, IPC_STAT, &shmid_ds);
+
+	tst_res(TINFO, "Number of attaches: %lu", shmid_ds.shm_nattch);
+	tst_res(TINFO, "Delete attached memory");
+
+	SAFE_SHMDT(sh_mem);
+	SAFE_SHMCTL(segment_id, IPC_STAT, &shmid_ds);
+
+	tst_res(TINFO, "Number of attaches: %lu", shmid_ds.shm_nattch);
+
+	SAFE_SHMCTL(segment_id, IPC_RMID, NULL);
+	segment_id = -1;
+
+	TST_EXP_EQ_LU(shmid_ds.shm_nattch, 0);
+}
+
+static void setup(void)
+{
+	key_id = GETIPCKEY() + 1;
+	page_size = getpagesize();
+
+	tst_res(TINFO, "Key id: %d", key_id);
+	tst_res(TINFO, "Page size: %d", page_size);
+
+	segment_size = 3 * page_size;
+}
+
+static void cleanup(void)
+{
+	if (segment_id != -1)
+		SAFE_SHMCTL(segment_id, IPC_RMID, NULL);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.cleanup = cleanup,
+};
-- 
2.35.3


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [LTP] [PATCH v5 1/3] Add SAFE_MPROTECT() macro
  2024-03-13  9:23 ` [LTP] [PATCH v5 1/3] Add SAFE_MPROTECT() macro Andrea Cervesato
@ 2024-03-13  9:56   ` Cyril Hrubis
  2024-03-13  9:59   ` Cyril Hrubis
  1 sibling, 0 replies; 7+ messages in thread
From: Cyril Hrubis @ 2024-03-13  9:56 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp

Hi!
> +static void prot_to_str(const int prot, char *buf)
> +{
> +	char *ptr = buf;
>

I would still put an explicit check for the buffer size here, so that we
are sure that the complete combination of READ|WRITE|EXEC would fit, but
I guess that it's fine as long as this is an internal static function
and not part of the API.

> +	if (prot == PROT_NONE) {
> +		strcpy(buf, "PROT_NONE");
> +		return;
> +	}
> +
> +	if (prot & PROT_READ) {
> +		strcpy(ptr, PROT_FLAG_STR(PROT_READ));
> +		ptr += sizeof(PROT_FLAG_STR(PROT_READ)) - 1;
> +	}
> +
> +	if (prot & PROT_WRITE) {
> +		strcpy(ptr, PROT_FLAG_STR(PROT_WRITE));
> +		ptr += sizeof(PROT_FLAG_STR(PROT_WRITE)) - 1;
> +	}
> +
> +	if (prot & PROT_EXEC) {
> +		strcpy(ptr, PROT_FLAG_STR(PROT_EXEC));
> +		ptr += sizeof(PROT_FLAG_STR(PROT_EXEC)) - 1;
> +	}
> +
> +	if (buf != ptr)
> +		ptr[-3] = 0;
> +}
> +
>  static inline void *safe_mmap(const char *file, const int lineno,
>                                void *addr, size_t length,
>                                int prot, int flags, int fd, off_t offset)
> @@ -287,6 +318,35 @@ static inline void *safe_mmap(const char *file, const int lineno,
>  	safe_mmap(__FILE__, __LINE__, (addr), (length), (prot), \
>  	(flags), (fd), (offset))
>  
> +static inline int safe_mprotect(const char *file, const int lineno,
> +	char *addr, size_t len, int prot)
> +{
> +	int rval;
> +	char *prot_buf;
> +
> +	prot_buf = (char*) safe_malloc(file, lineno, 0, 512);

Why are we allocating the buffer? Why not just prot_buf[512] ?

Also the cast to (char*) is never needed in C as void* is automatically
converted to any type of a pointer without explicit cast.


Otherwise it looks good. You can add my Reviewed-by: if you change the
malloc to an array on the stack.

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [LTP] [PATCH v5 2/3] Print prot flag when SAFE_MMAP() fails
  2024-03-13  9:23 ` [LTP] [PATCH v5 2/3] Print prot flag when SAFE_MMAP() fails Andrea Cervesato
@ 2024-03-13  9:57   ` Cyril Hrubis
  0 siblings, 0 replies; 7+ messages in thread
From: Cyril Hrubis @ 2024-03-13  9:57 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp

Hi!
>  include/tst_safe_macros.h | 10 ++++++++--
>  1 file changed, 8 insertions(+), 2 deletions(-)
> 
> diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
> index 15f914619..63ad46b85 100644
> --- a/include/tst_safe_macros.h
> +++ b/include/tst_safe_macros.h
> @@ -304,12 +304,18 @@ static inline void *safe_mmap(const char *file, const int lineno,
>                                int prot, int flags, int fd, off_t offset)
>  {
>  	void *rval;
> +	char *prot_buf;

Shouldn't we add the TDEBUG message here?

>  	rval = mmap(addr, length, prot, flags, fd, offset);
>  	if (rval == MAP_FAILED) {
> +		prot_buf = (char*) safe_malloc(file, lineno, 0, 512);
> +		prot_to_str(prot, prot_buf);
> +
>  		tst_brk_(file, lineno, TBROK | TERRNO,
> -			"mmap(%p,%zu,%d,%d,%d,%ld) failed",
> -			addr, length, prot, flags, fd, (long) offset);
> +			"mmap(%p,%zu,%s(%x),%d,%d,%ld) failed",
> +			addr, length, prot_buf, prot, flags, fd, (long) offset);
> +
> +		free(prot_buf);

This is fine as long as we switch to an on the stack array.

>  	}
>  
>  	return rval;
> -- 
> 2.35.3
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [LTP] [PATCH v5 1/3] Add SAFE_MPROTECT() macro
  2024-03-13  9:23 ` [LTP] [PATCH v5 1/3] Add SAFE_MPROTECT() macro Andrea Cervesato
  2024-03-13  9:56   ` Cyril Hrubis
@ 2024-03-13  9:59   ` Cyril Hrubis
  1 sibling, 0 replies; 7+ messages in thread
From: Cyril Hrubis @ 2024-03-13  9:59 UTC (permalink / raw)
  To: Andrea Cervesato; +Cc: ltp

Hi!
> +static inline int safe_mprotect(const char *file, const int lineno,
> +	char *addr, size_t len, int prot)
> +{
> +	int rval;
> +	char *prot_buf;
> +
> +	prot_buf = (char*) safe_malloc(file, lineno, 0, 512);
> +	prot_to_str(prot, prot_buf);
> +
> +	tst_res_(file, lineno, TDEBUG,
> +		"mprotect(%p, %ld, %s(%x))", addr, len, prot_buf, prot);
> +
> +	free(prot_buf);
> +
> +	rval = mprotect(addr, len, prot);
> +
> +	if (rval == -1) {
> +		tst_brk_(file, lineno, TBROK | TERRNO,
> +			"mprotect() failed");
> +	} else if (rval) {
> +		tst_brk_(file, lineno, TBROK | TERRNO,
> +			"Invalid mprotect() return value %d", rval);
> +	}


Ah, and can we please print the whole parameter list for mprotect() in
these two cases as well?

> +	return rval;
> +}
> +#define SAFE_MPROTECT(addr, len, prot) \
> +	safe_mprotect(__FILE__, __LINE__, (addr), (len), (prot))
> +
>  static inline int safe_ftruncate(const char *file, const int lineno,
>                                   int fd, off_t length)
>  {
> -- 
> 2.35.3
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

-- 
Cyril Hrubis
chrubis@suse.cz

-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2024-03-13 10:01 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-03-13  9:23 [LTP] [PATCH v5 0/3] SysV IPC bug reproducer Andrea Cervesato
2024-03-13  9:23 ` [LTP] [PATCH v5 1/3] Add SAFE_MPROTECT() macro Andrea Cervesato
2024-03-13  9:56   ` Cyril Hrubis
2024-03-13  9:59   ` Cyril Hrubis
2024-03-13  9:23 ` [LTP] [PATCH v5 2/3] Print prot flag when SAFE_MMAP() fails Andrea Cervesato
2024-03-13  9:57   ` Cyril Hrubis
2024-03-13  9:23 ` [LTP] [PATCH v5 3/3] Add shmat04 SysV IPC bug reproducer Andrea Cervesato

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox