diff mbox series

[RFC,1/9] lib: Add support for guarded buffers

Message ID 20190801092616.30553-2-chrubis@suse.cz
State Superseded
Headers show
Series [RFC,1/9] lib: Add support for guarded buffers | expand

Commit Message

Cyril Hrubis Aug. 1, 2019, 9:26 a.m. UTC
This commit adds a support for guarder buffers. Guarded buffer is a
buffer allocated so that there is PROT_NONE page immediatelly after the
end of the buffer i.e. any access after the buffer generates
SEGFAULT/EFAULT etc.

The library is hooked into the tst_test structure so that all you need
is to fill up an NULL terminated array of buffer pointers and sizes to
get the respective buffers allocated. The library supports allocating
memory in test runtime as well as well as allocating more complex
buffers, which currently are iovec vectors.

All buffers are freeed automatically at the end of the test.

Example usage looks like:

static struct foo *foo_ptr;
static struct iovec *iov;
static void *buf_ptr;
static char *id;
...

static void run(void)
{
	...

	foo_ptr->bar = 1;
	foo_ptr->buf = buf_ptr;

	...
}

static void setup(void)
{
	...

	id = strdup(string);

	...
}

static struct tst_test test = {
	...
	.bufs = (struct tst_buffers []) {
		{&foo_ptr, .size = sizeof(*foo_ptr)},
		{&buf_ptr, .size = BUF_SIZE},
		{&iov, .iov_sizes = (int[]){128, 32, -1},
		{}
	}
};

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 include/tst_buffers.h                       |  63 ++++++++++++
 include/tst_test.h                          |   6 ++
 lib/newlib_tests/.gitignore                 |   1 +
 lib/newlib_tests/test_guarded_buf.c         |  78 ++++++++++++++
 lib/tst_buffers.c                           | 106 ++++++++++++++++++++
 lib/tst_test.c                              |   5 +
 testcases/kernel/syscalls/accept/accept02.c |  41 ++++----
 7 files changed, 281 insertions(+), 19 deletions(-)
 create mode 100644 include/tst_buffers.h
 create mode 100644 lib/newlib_tests/test_guarded_buf.c
 create mode 100644 lib/tst_buffers.c

Comments

Jan Stancek Aug. 1, 2019, 10:39 a.m. UTC | #1
----- Original Message -----
> This commit adds a support for guarder buffers. Guarded buffer is a
> buffer allocated so that there is PROT_NONE page immediatelly after the
> end of the buffer i.e. any access after the buffer generates
> SEGFAULT/EFAULT etc.
> 
> The library is hooked into the tst_test structure so that all you need
> is to fill up an NULL terminated array of buffer pointers and sizes to
> get the respective buffers allocated. The library supports allocating
> memory in test runtime as well as well as allocating more complex
> buffers, which currently are iovec vectors.

Runtime alloc in loop could be an issue, do we need also runtime free?
Cyril Hrubis Aug. 1, 2019, 11:45 a.m. UTC | #2
Hi!
> > This commit adds a support for guarder buffers. Guarded buffer is a
> > buffer allocated so that there is PROT_NONE page immediatelly after the
> > end of the buffer i.e. any access after the buffer generates
> > SEGFAULT/EFAULT etc.
> > 
> > The library is hooked into the tst_test structure so that all you need
> > is to fill up an NULL terminated array of buffer pointers and sizes to
> > get the respective buffers allocated. The library supports allocating
> > memory in test runtime as well as well as allocating more complex
> > buffers, which currently are iovec vectors.
> 
> Runtime alloc in loop could be an issue, do we need also runtime free?

We can easily add it if we find it useful, so far all the usecases
were either already allocating buffers in setup or converted to do so.
Richard Palethorpe Aug. 2, 2019, 1:57 p.m. UTC | #3
Hello,

Jan Stancek <jstancek@redhat.com> writes:

> ----- Original Message -----
>> This commit adds a support for guarder buffers. Guarded buffer is a
>> buffer allocated so that there is PROT_NONE page immediatelly after the
>> end of the buffer i.e. any access after the buffer generates
>> SEGFAULT/EFAULT etc.
>> 
>> The library is hooked into the tst_test structure so that all you need
>> is to fill up an NULL terminated array of buffer pointers and sizes to
>> get the respective buffers allocated. The library supports allocating
>> memory in test runtime as well as well as allocating more complex
>> buffers, which currently are iovec vectors.
>
> Runtime alloc in loop could be an issue, do we need also runtime free?

I think tst_alloc needs a bit more documentation at the least. If we
have runtime free then we need to figure out which map the address
belongs to or what its offset is (if any).
Cyril Hrubis Aug. 2, 2019, 1:59 p.m. UTC | #4
Hi!
> >> This commit adds a support for guarder buffers. Guarded buffer is a
> >> buffer allocated so that there is PROT_NONE page immediatelly after the
> >> end of the buffer i.e. any access after the buffer generates
> >> SEGFAULT/EFAULT etc.
> >> 
> >> The library is hooked into the tst_test structure so that all you need
> >> is to fill up an NULL terminated array of buffer pointers and sizes to
> >> get the respective buffers allocated. The library supports allocating
> >> memory in test runtime as well as well as allocating more complex
> >> buffers, which currently are iovec vectors.
> >
> > Runtime alloc in loop could be an issue, do we need also runtime free?
> 
> I think tst_alloc needs a bit more documentation at the least.

I will write an paragraph to test-writing-guidelines.txt about this
functionality.

> If we have runtime free then we need to figure out which map the
> address belongs to or what its offset is (if any).

That's easy, we will store the returned pointer to the map structure
and use it for comparsion...
Richard Palethorpe Aug. 2, 2019, 2:03 p.m. UTC | #5
Hello,

Cyril Hrubis <chrubis@suse.cz> writes:

> Hi!
>> > This commit adds a support for guarder buffers. Guarded buffer is a
>> > buffer allocated so that there is PROT_NONE page immediatelly after the
>> > end of the buffer i.e. any access after the buffer generates
>> > SEGFAULT/EFAULT etc.
>> > 
>> > The library is hooked into the tst_test structure so that all you need
>> > is to fill up an NULL terminated array of buffer pointers and sizes to
>> > get the respective buffers allocated. The library supports allocating
>> > memory in test runtime as well as well as allocating more complex
>> > buffers, which currently are iovec vectors.
>> 
>> Runtime alloc in loop could be an issue, do we need also runtime free?
>
> We can easily add it if we find it useful, so far all the usecases
> were either already allocating buffers in setup or converted to do so.

I am just starting to convert one of the bpf tests and I am considering
just wrapping the systemcall or creating some helper func which takes
whatever buffer is supplied and copy it to a new gaurded buffer. It is
maybe not efficient with large buffer sizes, but in most cases I don't
think it would matter too much.
Cyril Hrubis Aug. 2, 2019, 2:20 p.m. UTC | #6
Hi!
> diff --git a/testcases/kernel/syscalls/accept/accept02.c b/testcases/kernel/syscalls/accept/accept02.c
> index df048ede4..1a0f625c9 100644
> --- a/testcases/kernel/syscalls/accept/accept02.c
> +++ b/testcases/kernel/syscalls/accept/accept02.c

Sigh looks like I've added this test conversion to this patch as a
mistake, I will move it to a separate patch in v2.
Cyril Hrubis Aug. 2, 2019, 2:23 p.m. UTC | #7
Hi!
> > If we have runtime free then we need to figure out which map the
> > address belongs to or what its offset is (if any).
> 
> That's easy, we will store the returned pointer to the map structure
> and use it for comparsion...

Or we even don't have to do that, we do have a buffer start address and
length so we just need to make sure that the pointer fits the range...
Richard Palethorpe Aug. 2, 2019, 2:36 p.m. UTC | #8
Hello,

Cyril Hrubis <chrubis@suse.cz> writes:

> Hi!
>> >> This commit adds a support for guarder buffers. Guarded buffer is a
>> >> buffer allocated so that there is PROT_NONE page immediatelly after the
>> >> end of the buffer i.e. any access after the buffer generates
>> >> SEGFAULT/EFAULT etc.
>> >> 
>> >> The library is hooked into the tst_test structure so that all you need
>> >> is to fill up an NULL terminated array of buffer pointers and sizes to
>> >> get the respective buffers allocated. The library supports allocating
>> >> memory in test runtime as well as well as allocating more complex
>> >> buffers, which currently are iovec vectors.
>> >
>> > Runtime alloc in loop could be an issue, do we need also runtime free?
>> 
>> I think tst_alloc needs a bit more documentation at the least.
>
> I will write an paragraph to test-writing-guidelines.txt about this
> functionality.
>
>> If we have runtime free then we need to figure out which map the
>> address belongs to or what its offset is (if any).
>
> That's easy, we will store the returned pointer to the map structure
> and use it for comparsion...

So that free() is an O(n) operation where n is the number of maps or you
will use a hash map to make it O(1)?
Cyril Hrubis Aug. 2, 2019, 2:50 p.m. UTC | #9
Hi!
> >> If we have runtime free then we need to figure out which map the
> >> address belongs to or what its offset is (if any).
> >
> > That's easy, we will store the returned pointer to the map structure
> > and use it for comparsion...
> 
> So that free() is an O(n) operation where n is the number of maps or you
> will use a hash map to make it O(1)?

I doubt that we will ever allocate more than a few buffers, so it's
perfectly fine that way. Also if you keep allocating and freeing buffer
in a loop it would be at the start of the list, so it would be O(1) as
well.

The only patological case would be allocating thousands of buffers and
then freeing them in a reversed order, which would be O(n^2).

Other options would be storing the pointer to the map before the buffer,
just as malloc does, but I doubt that we will ever need that.
Li Wang Aug. 3, 2019, 12:55 p.m. UTC | #10
Hi Cyril,

This is a quite good idea to involve guard buffer in LTP testing. And
you patch set looks very clean & tidy, just have some few comments in
below.

On Thu, Aug 1, 2019 at 5:27 PM Cyril Hrubis <chrubis@suse.cz> wrote:
>
> This commit adds a support for guarder buffers. Guarded buffer is a
> buffer allocated so that there is PROT_NONE page immediatelly after the
> end of the buffer i.e. any access after the buffer generates
> SEGFAULT/EFAULT etc.
>
> The library is hooked into the tst_test structure so that all you need
> is to fill up an NULL terminated array of buffer pointers and sizes to
> get the respective buffers allocated. The library supports allocating
> memory in test runtime as well as well as allocating more complex
> buffers, which currently are iovec vectors.
>
> All buffers are freeed automatically at the end of the test.
...

> + * Allocates size bytes, returns pointer to the allocated buffer.
> + */
> +void *tst_alloc(size_t size);

What about drawing a simple picture in the code comments? That can
help people to understand what kind of buffer structure the
tst_alloc() returned.

/*
 * Allocates size bytes, returns pointer to the allocated buffer.
 *
 * This is the structure of the allocated buferr:
 *
 * |<--  1 page  -->|                 |<--  1 page  -->|
 *
 * -----------------------------------------------------
 * | buf_shift | <-- bufs[i].size --> |  1 guard page  |
 * -----------------------------------------------------
 */
void *tst_alloc(size_t size);

> +++ b/include/tst_test.h
> @@ -35,6 +35,7 @@
>  #include "tst_path_has_mnt_flags.h"
>  #include "tst_sys_conf.h"
>  #include "tst_coredump.h"
> +#include "tst_buffers.h"
>
>  /*
>   * Reports testcase result.
> @@ -200,6 +201,11 @@ struct tst_test {
>          * test.
>          */
>         const char *const *needs_kconfigs;
> +
> +       /*
> +        * NULL-terminated array to be allocated buffers.
> +        */
> +       struct tst_buffers *bufs;

I tend to agree with Richard for this. Looks like adding such a new
field in tst_test struct is a little bit complicated. Maybe we can
define a series macro for doing that, which something likes:

TST_INIT_GUARD_BUFFER(ptr, size)
TST_INIT_IOVEC_GUARD_BUFFER(ptr, iov_sizes)

then, testcase just calling it in setup() if needed.

--
Regards,
Li Wang
Richard Palethorpe Aug. 6, 2019, 7:36 a.m. UTC | #11
Hello,

Li Wang <liwang@redhat.com> writes:
>
> I tend to agree with Richard for this. Looks like adding such a new
> field in tst_test struct is a little bit complicated. Maybe we can
> define a series macro for doing that, which something likes:
>
> TST_INIT_GUARD_BUFFER(ptr, size)

I think tst_alloc() is OK (although maybe it should be
tst_guarded_alloc()), but the API is missing its inverse; tst_free().

> TST_INIT_IOVEC_GUARD_BUFFER(ptr, iov_sizes)

Or I guess, tst_alloc() could take tst_buffer(s) as its argument and
return the right type of buffer based on that.

>
> then, testcase just calling it in setup() if needed.

I don't think allocating the buffers in tst_test is a bad idea in
some/most cases. I think the problem is that some primitive, low level
functions are missing, which will make edge cases difficult to deal
with.

--
Thank you,
Richard.
Richard Palethorpe Aug. 6, 2019, 9:03 a.m. UTC | #12
Hi,

Cyril Hrubis <chrubis@suse.cz> writes:
> +void tst_free_all(void)
> +{
> +	struct map *i = maps;
> +
> +	while (i) {
> +		struct map *j = i;
> +		tst_res(TINFO, "Freeing %p %zu", i->addr, i->size);

This seems like debug info to me. Not really useful most of the time.

> +		SAFE_MUNMAP(i->addr, i->size);
> +		i = i->next;
> +		free(j);
> +	}
> +
> +	maps = NULL;
> +}
Cyril Hrubis Aug. 8, 2019, 9:06 a.m. UTC | #13
Hi!
> > +void tst_free_all(void)
> > +{
> > +	struct map *i = maps;
> > +
> > +	while (i) {
> > +		struct map *j = i;
> > +		tst_res(TINFO, "Freeing %p %zu", i->addr, i->size);
> 
> This seems like debug info to me. Not really useful most of the time.

Yes, this is a leftover.

I do wonder if we should print a message first time the tst_alloc() is
called so that it's clear that the test is using guarded buffers.

> > +		SAFE_MUNMAP(i->addr, i->size);
> > +		i = i->next;
> > +		free(j);
> > +	}
> > +
> > +	maps = NULL;
> > +}
> 
> -- 
> Thank you,
> Richard.
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp
Li Wang Aug. 8, 2019, 9:13 a.m. UTC | #14
> > This seems like debug info to me. Not really useful most of the time.
>
> Yes, this is a leftover.
>
> I do wonder if we should print a message first time the tst_alloc() is
> called so that it's clear that the test is using guarded buffers.

Sounds necessary. Or should we need a way for silent using?
Richard Palethorpe Aug. 8, 2019, 3:41 p.m. UTC | #15
Hello,

Cyril Hrubis <chrubis@suse.cz> writes:

> Hi!
>> > +void tst_free_all(void)
>> > +{
>> > +	struct map *i = maps;
>> > +
>> > +	while (i) {
>> > +		struct map *j = i;
>> > +		tst_res(TINFO, "Freeing %p %zu", i->addr, i->size);
>> 
>> This seems like debug info to me. Not really useful most of the time.
>
> Yes, this is a leftover.
>
> I do wonder if we should print a message first time the tst_alloc() is
> called so that it's clear that the test is using guarded buffers.

Maybe some summary info.

>
>> > +		SAFE_MUNMAP(i->addr, i->size);
>> > +		i = i->next;
>> > +		free(j);
>> > +	}
>> > +
>> > +	maps = NULL;
>> > +}
>> 
>> -- 
>> Thank you,
>> Richard.
>> 
>> -- 
>> Mailing list info: https://lists.linux.it/listinfo/ltp
diff mbox series

Patch

diff --git a/include/tst_buffers.h b/include/tst_buffers.h
new file mode 100644
index 000000000..d19ac8cf0
--- /dev/null
+++ b/include/tst_buffers.h
@@ -0,0 +1,63 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_BUFFERS_H__
+#define TST_BUFFERS_H__
+
+/*
+ * Buffer description consist of a pointer to a pointer and buffer type/size
+ * encoded as a different structure members.
+ *
+ * Only one of the size and iov_sizes can be set at a time.
+ */
+struct tst_buffers {
+	/*
+	 * This pointer points to a buffer pointer.
+	 */
+	void *ptr;
+	/*
+	 * Buffer size.
+	 */
+	size_t size;
+	/*
+	 * Array of iov buffer sizes terminated by -1.
+	 */
+	int *iov_sizes;
+};
+
+/*
+ * Allocates buffers based on the tst_buffers structure.
+ *
+ * @bufs NULL terminated array of test buffer descriptions.
+ *
+ * This is called from the test library if the tst_test->bufs pointer is set.
+ */
+void tst_buffers_alloc(struct tst_buffers bufs[]);
+
+/*
+ * strdup() that callls tst_alloc().
+ */
+char *tst_strdup(const char *str);
+
+/*
+ * Allocates size bytes, returns pointer to the allocated buffer.
+ */
+void *tst_alloc(size_t size);
+
+/*
+ * Allocates iovec structure including the buffers.
+ *
+ * @sizes -1 terminated array of buffer sizes.
+ */
+struct iovec *tst_iovec_alloc(int sizes[]);
+
+/*
+ * Frees all allocated buffers.
+ *
+ * This is called at the end of the test automatically.
+ */
+void tst_free_all(void);
+
+#endif	/* TST_BUFFERS_H__ */
diff --git a/include/tst_test.h b/include/tst_test.h
index 2e07ff16b..cdeaf6ad0 100644
--- a/include/tst_test.h
+++ b/include/tst_test.h
@@ -35,6 +35,7 @@ 
 #include "tst_path_has_mnt_flags.h"
 #include "tst_sys_conf.h"
 #include "tst_coredump.h"
+#include "tst_buffers.h"
 
 /*
  * Reports testcase result.
@@ -200,6 +201,11 @@  struct tst_test {
 	 * test.
 	 */
 	const char *const *needs_kconfigs;
+
+	/*
+	 * NULL-terminated array to be allocated buffers.
+	 */
+	struct tst_buffers *bufs;
 };
 
 /*
diff --git a/lib/newlib_tests/.gitignore b/lib/newlib_tests/.gitignore
index d92b89872..6788ddf90 100644
--- a/lib/newlib_tests/.gitignore
+++ b/lib/newlib_tests/.gitignore
@@ -26,3 +26,4 @@  test_exec
 test_exec_child
 test_kconfig
 variant
+test_guarded_buf
diff --git a/lib/newlib_tests/test_guarded_buf.c b/lib/newlib_tests/test_guarded_buf.c
new file mode 100644
index 000000000..2951dce23
--- /dev/null
+++ b/lib/newlib_tests/test_guarded_buf.c
@@ -0,0 +1,78 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+/*
+ * Test that acces after guarded buffer causes segfault.
+ */
+
+#include <stdlib.h>
+#include <sys/wait.h>
+#include "tst_test.h"
+
+#define BUF1_LEN 10
+#define BUF2_LEN 4096
+#define BUF3_LEN 12004
+
+static char *buf1;
+static char *buf2;
+static char *buf3;
+
+static void do_test(unsigned int n)
+{
+	int pid = SAFE_FORK();
+	int status;
+
+	if (!pid) {
+		switch (n) {
+		case 0:
+			buf1[BUF1_LEN - 1] = 0;
+		break;
+		case 1:
+			buf2[BUF2_LEN - 1] = 0;
+		break;
+		case 2:
+			buf3[BUF3_LEN - 1] = 0;
+		break;
+		case 3:
+			buf1[BUF1_LEN] = 0;
+		break;
+		case 4:
+			buf2[BUF2_LEN] = 0;
+		break;
+		case 5:
+			buf3[BUF3_LEN] = 0;
+		break;
+		}
+
+		exit(0);
+	}
+
+	SAFE_WAITPID(pid, &status, 0);
+
+	if (n < 3) {
+		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+			tst_res(TPASS, "Exitted normally");
+			return;
+		}
+	} else {
+		if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) {
+			tst_res(TPASS, "Killed by SIGSEGV");
+			return;
+		}
+	}
+
+	tst_res(TFAIL, "Child %s", tst_strstatus(status));
+}
+
+static struct tst_test test = {
+	.forks_child = 1,
+	.test = do_test,
+	.tcnt = 6,
+	.bufs = (struct tst_buffers []) {
+		{&buf1, .size = BUF1_LEN},
+		{&buf2, .size = BUF2_LEN},
+		{&buf3, .size = BUF3_LEN},
+	}
+};
diff --git a/lib/tst_buffers.c b/lib/tst_buffers.c
new file mode 100644
index 000000000..c4b2859d1
--- /dev/null
+++ b/lib/tst_buffers.c
@@ -0,0 +1,106 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <sys/mman.h>
+#include <stdlib.h>
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+struct map {
+	void *addr;
+	size_t size;
+	struct map *next;
+};
+
+static struct map *maps;
+
+void *tst_alloc(size_t size)
+{
+	size_t page_size = getpagesize();
+	unsigned int pages = (size / page_size) + !!(size % page_size) + 1;
+	void *ret;
+	struct map *map = SAFE_MALLOC(sizeof(struct map));
+
+	ret = SAFE_MMAP(NULL, page_size * pages, PROT_READ | PROT_WRITE,
+	                MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+
+	mprotect(ret + (pages-1) * page_size, page_size, PROT_NONE);
+
+	map->addr = ret;
+	map->size = pages * page_size;
+	map->next = maps;
+	maps = map;
+
+	if (size % page_size)
+		ret += page_size - (size % page_size);
+
+	return ret;
+}
+
+static int count_iovec(int *sizes)
+{
+	int ret = 0;
+
+	while (sizes[ret++] != -1);
+
+	return ret - 1;
+}
+
+struct iovec *tst_iovec_alloc(int sizes[])
+{
+	int i, cnt = count_iovec(sizes);
+	struct iovec *iovec;
+
+	if (cnt <= 0)
+		return NULL;
+
+	iovec = tst_alloc(sizeof(struct iovec) * cnt);
+
+	for (i = 0; i < cnt; i++) {
+		if (sizes[i]) {
+			iovec[i].iov_base = tst_alloc(sizes[i]);
+			iovec[i].iov_len = sizes[i];
+		} else {
+			iovec[i].iov_base = NULL;
+			iovec[i].iov_base = 0;
+		}
+	}
+
+	return iovec;
+}
+
+void tst_buffers_alloc(struct tst_buffers bufs[])
+{
+	unsigned int i;
+
+	for (i = 0; bufs[i].ptr; i++) {
+		if (bufs[i].size)
+			*((void**)bufs[i].ptr) = tst_alloc(bufs[i].size);
+		else
+			*((void**)bufs[i].ptr) = tst_iovec_alloc(bufs[i].iov_sizes);
+	}
+}
+
+char *tst_strdup(const char *str)
+{
+	size_t len = strlen(str);
+	char *ret = tst_alloc(len + 1);
+	return strcpy(ret, str);
+}
+
+void tst_free_all(void)
+{
+	struct map *i = maps;
+
+	while (i) {
+		struct map *j = i;
+		tst_res(TINFO, "Freeing %p %zu", i->addr, i->size);
+		SAFE_MUNMAP(i->addr, i->size);
+		i = i->next;
+		free(j);
+	}
+
+	maps = NULL;
+}
diff --git a/lib/tst_test.c b/lib/tst_test.c
index 245e287fa..8dc71dbb3 100644
--- a/lib/tst_test.c
+++ b/lib/tst_test.c
@@ -283,6 +283,8 @@  static void do_test_cleanup(void)
 	if (tst_test->cleanup)
 		tst_test->cleanup();
 
+	tst_free_all();
+
 	tst_brk_handler = tst_vbrk_;
 }
 
@@ -802,6 +804,9 @@  static void do_setup(int argc, char *argv[])
 
 	setup_ipc();
 
+	if (tst_test->bufs)
+		tst_buffers_alloc(tst_test->bufs);
+
 	if (needs_tmpdir() && !tst_tmpdir_created())
 		tst_tmpdir();
 
diff --git a/testcases/kernel/syscalls/accept/accept02.c b/testcases/kernel/syscalls/accept/accept02.c
index df048ede4..1a0f625c9 100644
--- a/testcases/kernel/syscalls/accept/accept02.c
+++ b/testcases/kernel/syscalls/accept/accept02.c
@@ -33,10 +33,9 @@  static int client_sockfd;
 static int server_port;
 static socklen_t addr_len;
 
-static struct sockaddr_in server_addr;
-static struct sockaddr_in client_addr;
-static struct group_req mc_group;
-
+static struct sockaddr_in *server_addr;
+static struct sockaddr_in *client_addr;
+static struct group_req *mc_group;
 
 static void *server_thread(void *arg)
 {
@@ -44,27 +43,27 @@  static void *server_thread(void *arg)
 
 	op = 1;
 	op_len = sizeof(op);
-	mc_group_len = sizeof(mc_group);
+	mc_group_len = sizeof(*mc_group);
 
 	server_sockfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
 
 	SAFE_SETSOCKOPT(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &op, op_len);
 	SAFE_SETSOCKOPT(server_sockfd, SOL_IP, MCAST_JOIN_GROUP,
-			&mc_group, mc_group_len);
+			mc_group, mc_group_len);
 
-	SAFE_BIND(server_sockfd, (struct sockaddr *)&server_addr, addr_len);
+	SAFE_BIND(server_sockfd, (struct sockaddr *)server_addr, addr_len);
 	SAFE_LISTEN(server_sockfd, 1);
 
 	TST_CHECKPOINT_WAKE(0);
 
-	TEST(accept(server_sockfd, (struct sockaddr *)&client_addr, &addr_len));
+	TEST(accept(server_sockfd, (struct sockaddr *)client_addr, &addr_len));
 	if (TST_RET == -1)
 		tst_brk(TBROK | TTERRNO, "Could not accept connection");
 
 	clone_server_sockfd = TST_RET;
 
 	TEST(setsockopt(clone_server_sockfd, SOL_IP, MCAST_LEAVE_GROUP,
-			&mc_group, mc_group_len));
+			mc_group, mc_group_len));
 
 	if (TST_RET != -1)
 		tst_res(TFAIL, "Multicast group was copied!");
@@ -80,9 +79,9 @@  static void *server_thread(void *arg)
 static void *client_thread(void *arg)
 {
 	client_sockfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
-	SAFE_BIND(client_sockfd, (struct sockaddr *)&client_addr, addr_len);
+	SAFE_BIND(client_sockfd, (struct sockaddr *)client_addr, addr_len);
 
-	SAFE_CONNECT(client_sockfd, (struct sockaddr *)&server_addr, addr_len);
+	SAFE_CONNECT(client_sockfd, (struct sockaddr *)server_addr, addr_len);
 
 	SAFE_CLOSE(client_sockfd);
 	return arg;
@@ -92,8 +91,8 @@  static void run(void)
 {
 	pthread_t server_thr, client_thr;
 
-	server_addr.sin_port = server_port;
-	client_addr.sin_port = htons(0);
+	server_addr->sin_port = server_port;
+	client_addr->sin_port = htons(0);
 
 	SAFE_PTHREAD_CREATE(&server_thr, NULL, server_thread, NULL);
 	TST_CHECKPOINT_WAIT(0);
@@ -107,16 +106,20 @@  static void setup(void)
 {
 	struct sockaddr_in *mc_group_addr;
 
-	mc_group.gr_interface = 0;
-	mc_group_addr = (struct sockaddr_in *) &mc_group.gr_group;
+	server_addr = tst_alloc(sizeof(*server_addr));
+	client_addr = tst_alloc(sizeof(*client_addr));
+	mc_group = tst_alloc(sizeof(*mc_group));
+
+	mc_group->gr_interface = 0;
+	mc_group_addr = (struct sockaddr_in *) &mc_group->gr_group;
 	mc_group_addr->sin_family = AF_INET;
 	inet_aton(MULTICASTIP, &mc_group_addr->sin_addr);
 
-	server_addr.sin_family = AF_INET;
-	inet_aton(LOCALHOSTIP, &server_addr.sin_addr);
+	server_addr->sin_family = AF_INET;
+	inet_aton(LOCALHOSTIP, &server_addr->sin_addr);
 
-	client_addr.sin_family = AF_INET;
-	client_addr.sin_addr.s_addr = htons(INADDR_ANY);
+	client_addr->sin_family = AF_INET;
+	client_addr->sin_addr.s_addr = htons(INADDR_ANY);
 
 	addr_len = sizeof(struct sockaddr_in);