diff mbox series

[v2,4/4] syscalls/statfs: Accept segfault instead of EFAULT

Message ID 20220822113919.196953-5-tudor.cretu@arm.com
State Superseded
Headers show
Series syscalls: Fix various syscall tests when compiled with Musl | expand

Commit Message

Tudor Cretu Aug. 22, 2022, 11:39 a.m. UTC
The [f]statfs02 testsuites check that [f]statfs returns EFUALT when the
provided buf parameter is invalid. There are cases in which the supported
libcs don't exhibit this behaviour.

glibc versions newer than 2.34 and on systems that support [f]statfs64,
call the syscall with a local struct statfs and then copy the result
into buf. This throws a segfault for an invalid buf. musl dereferences buf
before the syscall is called and, similarly, throws a segfault.

Implement a sighandler to handle the cases where a segfault is thrown
instead of returning EFAULT.

Signed-off-by: Tudor Cretu <tudor.cretu@arm.com>
---
 testcases/kernel/syscalls/fstatfs/fstatfs02.c | 60 ++++++++++++++-----
 testcases/kernel/syscalls/statfs/statfs02.c   | 32 +++++++++-
 2 files changed, 73 insertions(+), 19 deletions(-)

Comments

Cyril Hrubis Aug. 22, 2022, 2:11 p.m. UTC | #1
>  int main(int ac, char **av)
>  {
>  	int lc;
> @@ -67,23 +73,20 @@ int main(int ac, char **av)
>  		tst_count = 0;
>  
>  		for (i = 0; i < TST_TOTAL; i++) {
> +			sig_caught = 0;
> +			if (sigsetjmp(env, 1) == 0)
> +				fstatfs_verify(&TC[i]);
>  
> -			TEST(fstatfs(TC[i].fd, TC[i].sbuf));
> +			if (!sig_caught)
> +				continue;
>  
> -			if (TEST_RETURN != -1) {
> -				tst_resm(TFAIL, "call succeeded unexpectedly");
> +			if (TC[i].error == EFAULT && sig_caught == SIGSEGV) {
> +				tst_resm(TINFO, "received SIGSEGV instead of returning EFAULT");
> +				tst_resm(TPASS | TTERRNO, "expected failure");

This can be just a signle message tst_resm(TPASS | TERRNO, "Got SIGSEGV intead of EFAULT");

>  				continue;
>  			}
>  
> -			if (TEST_ERRNO == TC[i].error) {
> -				tst_resm(TPASS, "expected failure - "
> -					 "errno = %d : %s", TEST_ERRNO,
> -					 strerror(TEST_ERRNO));
> -			} else {
> -				tst_resm(TFAIL, "unexpected error - %d : %s - "
> -					 "expected %d", TEST_ERRNO,
> -					 strerror(TEST_ERRNO), TC[i].error);
> -			}
> +			tst_resm(TFAIL, "Received an unexpected signal: %d", sig_caught);
>  		}
>  	}
>  	cleanup();
> @@ -91,9 +94,16 @@ int main(int ac, char **av)
>  	tst_exit();
>  }
>  
> +static void sighandler(int sig)
> +{
> +	sig_caught = sig;
> +	siglongjmp(env, 1);
> +
> +}
> +
>  static void setup(void)
>  {
> -	tst_sig(NOFORK, DEF_HANDLER, cleanup);
> +	tst_sig(NOFORK, sighandler, cleanup);

Can we just setup handler for the SIGSEGV signal and keep everything
else for the DEF_HANDLER?

>  	TEST_PAUSE;
>  
> @@ -103,6 +113,24 @@ static void setup(void)
>  #endif
>  }
>  
> +static void fstatfs_verify(const struct test_case_t *test)
> +{
> +	TEST(fstatfs(test->fd, test->sbuf));
> +
> +	if (TEST_RETURN != -1) {
> +		tst_resm(TFAIL, "call succeeded unexpectedly");
> +		return;
> +	}
> +
> +	if (TEST_ERRNO == test->error) {
> +		tst_resm(TPASS, "expected failure - errno = %d : %s",
> +			 TEST_ERRNO, strerror(TEST_ERRNO));
> +	} else {
> +		tst_resm(TFAIL, "unexpected error - %d : %s - expected %d",
> +			 TEST_ERRNO, strerror(TEST_ERRNO), test->error);
> +	}
> +}

If we converted the test to the new test API this would be a single line as:

	TST_EXP_FAIL(fstatfs(test->fd, test->sbuf), test->error, "fstatfs()");

Generally with the new test api the code would be much shorter...
diff mbox series

Patch

diff --git a/testcases/kernel/syscalls/fstatfs/fstatfs02.c b/testcases/kernel/syscalls/fstatfs/fstatfs02.c
index db2230f82..e46b9df23 100644
--- a/testcases/kernel/syscalls/fstatfs/fstatfs02.c
+++ b/testcases/kernel/syscalls/fstatfs/fstatfs02.c
@@ -21,6 +21,8 @@ 
  *	Testcase to check fstatfs() sets errno correctly.
  */
 
+#include <setjmp.h>
+#include <signal.h>
 #include <sys/vfs.h>
 #include <sys/types.h>
 #include <sys/statfs.h>
@@ -28,9 +30,6 @@ 
 #include "test.h"
 #include "safe_macros.h"
 
-static void setup(void);
-static void cleanup(void);
-
 char *TCID = "fstatfs02";
 
 static struct statfs buf;
@@ -53,6 +52,13 @@  static struct test_case_t {
 
 int TST_TOTAL = ARRAY_SIZE(TC);
 
+static int sig_caught;
+static sigjmp_buf env;
+
+static void setup(void);
+static void cleanup(void);
+static void fstatfs_verify(const struct test_case_t *);
+
 int main(int ac, char **av)
 {
 	int lc;
@@ -67,23 +73,20 @@  int main(int ac, char **av)
 		tst_count = 0;
 
 		for (i = 0; i < TST_TOTAL; i++) {
+			sig_caught = 0;
+			if (sigsetjmp(env, 1) == 0)
+				fstatfs_verify(&TC[i]);
 
-			TEST(fstatfs(TC[i].fd, TC[i].sbuf));
+			if (!sig_caught)
+				continue;
 
-			if (TEST_RETURN != -1) {
-				tst_resm(TFAIL, "call succeeded unexpectedly");
+			if (TC[i].error == EFAULT && sig_caught == SIGSEGV) {
+				tst_resm(TINFO, "received SIGSEGV instead of returning EFAULT");
+				tst_resm(TPASS | TTERRNO, "expected failure");
 				continue;
 			}
 
-			if (TEST_ERRNO == TC[i].error) {
-				tst_resm(TPASS, "expected failure - "
-					 "errno = %d : %s", TEST_ERRNO,
-					 strerror(TEST_ERRNO));
-			} else {
-				tst_resm(TFAIL, "unexpected error - %d : %s - "
-					 "expected %d", TEST_ERRNO,
-					 strerror(TEST_ERRNO), TC[i].error);
-			}
+			tst_resm(TFAIL, "Received an unexpected signal: %d", sig_caught);
 		}
 	}
 	cleanup();
@@ -91,9 +94,16 @@  int main(int ac, char **av)
 	tst_exit();
 }
 
+static void sighandler(int sig)
+{
+	sig_caught = sig;
+	siglongjmp(env, 1);
+
+}
+
 static void setup(void)
 {
-	tst_sig(NOFORK, DEF_HANDLER, cleanup);
+	tst_sig(NOFORK, sighandler, cleanup);
 
 	TEST_PAUSE;
 
@@ -103,6 +113,24 @@  static void setup(void)
 #endif
 }
 
+static void fstatfs_verify(const struct test_case_t *test)
+{
+	TEST(fstatfs(test->fd, test->sbuf));
+
+	if (TEST_RETURN != -1) {
+		tst_resm(TFAIL, "call succeeded unexpectedly");
+		return;
+	}
+
+	if (TEST_ERRNO == test->error) {
+		tst_resm(TPASS, "expected failure - errno = %d : %s",
+			 TEST_ERRNO, strerror(TEST_ERRNO));
+	} else {
+		tst_resm(TFAIL, "unexpected error - %d : %s - expected %d",
+			 TEST_ERRNO, strerror(TEST_ERRNO), test->error);
+	}
+}
+
 static void cleanup(void)
 {
 #ifndef UCLINUX
diff --git a/testcases/kernel/syscalls/statfs/statfs02.c b/testcases/kernel/syscalls/statfs/statfs02.c
index 279665f86..7f150d1d9 100644
--- a/testcases/kernel/syscalls/statfs/statfs02.c
+++ b/testcases/kernel/syscalls/statfs/statfs02.c
@@ -32,6 +32,8 @@ 
  *		ELOOP.
  */
 
+#include <setjmp.h>
+#include <signal.h>
 #include <sys/types.h>
 #include <sys/statfs.h>
 #include <sys/stat.h>
@@ -70,6 +72,10 @@  static struct test_case_t {
 };
 
 int TST_TOTAL = ARRAY_SIZE(TC);
+
+static int sig_caught;
+static sigjmp_buf env;
+
 static void setup(void);
 static void cleanup(void);
 static void statfs_verify(const struct test_case_t *);
@@ -85,17 +91,37 @@  int main(int ac, char **av)
 
 	for (lc = 0; TEST_LOOPING(lc); lc++) {
 		tst_count = 0;
-		for (i = 0; i < TST_TOTAL; i++)
-			statfs_verify(&TC[i]);
+		for (i = 0; i < TST_TOTAL; i++) {
+			sig_caught = 0;
+			if (sigsetjmp(env, 1) == 0)
+				statfs_verify(&TC[i]);
+
+			if (!sig_caught)
+				continue;
+
+			if (TC[i].exp_error == EFAULT && sig_caught == SIGSEGV) {
+				tst_resm(TINFO, "received SIGSEGV instead of returning EFAULT");
+				tst_resm(TPASS | TTERRNO, "expected failure");
+				continue;
+			}
+
+			tst_resm(TFAIL, "Received an unexpected signal: %d", sig_caught);
+		}
 	}
 
 	cleanup();
 	tst_exit();
 }
 
+static void sighandler(int sig)
+{
+	sig_caught = sig;
+	siglongjmp(env, 1);
+}
+
 static void setup(void)
 {
-	tst_sig(NOFORK, DEF_HANDLER, cleanup);
+	tst_sig(NOFORK, sighandler, cleanup);
 
 	TEST_PAUSE;