* [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