Message ID | 1572613170-20757-1-git-send-email-xuyang2018.jy@cn.fujitsu.com |
---|---|
State | Changes Requested |
Headers | show |
Series | [v3] syscalls/prctl02: add more error tests | expand |
Hi! > #include <errno.h> > #include <signal.h> > #include <sys/prctl.h> > - > +#include <linux/filter.h> > +#include <linux/capability.h> > +#include <unistd.h> > +#include <stdlib.h> > +#include <stddef.h> > +#include "config.h" > +#include "lapi/prctl.h" > +#include "lapi/seccomp.h" > +#include "lapi/syscalls.h" > #include "tst_test.h" > +#include "tst_capability.h" > > #define OPTION_INVALID 999 > #define INVALID_ARG 999 > > +static const struct sock_filter strict_filter[] = { > + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof (struct seccomp_data, nr))), > + > + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_close, 5, 0), > + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_exit, 4, 0), > + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_wait4, 3, 0), > + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_write, 2, 0), > + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_clone, 1, 0), > + > + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), > + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) > +}; > + > +static const struct sock_fprog strict = { > + .len = (unsigned short)ARRAY_SIZE(strict_filter), > + .filter = (struct sock_filter *)strict_filter > +}; We do have the exact same bytecode in the prctl04.c, can we put it to a header and include it in both tests? Or alternatively do we need more than just one-liner with BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) here? > static struct tcase { > int option; > unsigned long arg2; > + unsigned long arg3; > int exp_errno; > + int bad_addr; > } tcases[] = { > - {OPTION_INVALID, 0, EINVAL}, > - {PR_SET_PDEATHSIG, INVALID_ARG, EINVAL}, > + {OPTION_INVALID, 0, 0, EINVAL, 0}, > + {PR_SET_PDEATHSIG, INVALID_ARG, 0, EINVAL, 0}, > + {PR_SET_DUMPABLE, 2, 0, EINVAL, 0}, > + {PR_SET_NAME, 0, 0, EFAULT, 1}, > + {PR_SET_SECCOMP, 2, 0, EFAULT, 1}, > + {PR_SET_SECCOMP, 2, 2, EACCES, 0}, > + {PR_SET_TIMING, 1, 0, EINVAL, 0}, > +#ifdef HAVE_DECL_PR_SET_NO_NEW_PRIVS > + {PR_SET_NO_NEW_PRIVS, 0, 0, EINVAL, 0}, > + {PR_SET_NO_NEW_PRIVS, 1, 1, EINVAL, 0}, > + {PR_GET_NO_NEW_PRIVS, 1, 0, EINVAL, 0}, > +#endif > +#ifdef HAVE_DECL_PR_SET_THP_DISABLE > + {PR_SET_THP_DISABLE, 0, 1, EINVAL, 0}, > + {PR_GET_THP_DISABLE, 1, 0, EINVAL, 0}, > +#endif > +#ifdef HAVE_DECL_PR_CAP_AMBIENT > + {PR_CAP_AMBIENT, 2, 1, EINVAL, 0}, > +#endif > +#ifdef HAVE_DECL_PR_GET_SPECULATION_CTR > + {PR_GET_SPECULATION_CTRL, 1, 0, EINVAL, 0}, > +#endif > + {PR_SET_SECUREBITS, 0, 0, EPERM, 0}, > + {PR_CAPBSET_DROP, 1, 0, EPERM, 0}, > }; > > static void verify_prctl(unsigned int n) > { > struct tcase *tc = &tcases[n]; > > - TEST(prctl(tc->option, tc->arg2)); > + if (tc->arg3 == 2) > + tc->arg3 = (unsigned long)&strict; > + if (tc->bad_addr) { > + if (tc->arg2) > + tc->arg3 = (unsigned long)tst_get_bad_addr(NULL); > + else > + tc->arg2 = (unsigned long)tst_get_bad_addr(NULL); > + } I do not like this hackery, can't we just change the test to use pointers to pointers and initialize global variables in the test setup as we usually do? > + TEST(prctl(tc->option, tc->arg2, tc->arg3)); > if (TST_RET == 0) { > tst_res(TFAIL, "prctl() succeeded unexpectedly"); > return; > @@ -38,7 +123,10 @@ static void verify_prctl(unsigned int n) > if (tc->exp_errno == TST_ERR) { > tst_res(TPASS | TTERRNO, "prctl() failed as expected"); > } else { > - tst_res(TFAIL | TTERRNO, "prctl() failed unexpectedly, expected %s", > + if (tc->option == PR_SET_SECCOMP && TST_ERR == EINVAL) > + tst_res(TCONF, "current system was not built with CONFIG_SECCOMP."); > + else > + tst_res(TFAIL | TTERRNO, "prctl() failed unexpectedly, expected %s", > tst_strerrno(tc->exp_errno)); > } > } > @@ -46,4 +134,9 @@ static void verify_prctl(unsigned int n) > static struct tst_test test = { > .tcnt = ARRAY_SIZE(tcases), > .test = verify_prctl, > + .caps = (struct tst_cap []) { > + TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), > + TST_CAP(TST_CAP_DROP, CAP_SETPCAP), > + {} > + }, > }; > -- > 2.18.0 > > > > > -- > Mailing list info: https://lists.linux.it/listinfo/ltp
on 2019/11/07 22:54, Cyril Hrubis wrote: > Hi! >> #include <errno.h> >> #include <signal.h> >> #include <sys/prctl.h> >> - >> +#include <linux/filter.h> >> +#include <linux/capability.h> >> +#include <unistd.h> >> +#include <stdlib.h> >> +#include <stddef.h> >> +#include "config.h" >> +#include "lapi/prctl.h" >> +#include "lapi/seccomp.h" >> +#include "lapi/syscalls.h" >> #include "tst_test.h" >> +#include "tst_capability.h" >> >> #define OPTION_INVALID 999 >> #define INVALID_ARG 999 >> >> +static const struct sock_filter strict_filter[] = { >> + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof (struct seccomp_data, nr))), >> + >> + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_close, 5, 0), >> + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_exit, 4, 0), >> + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_wait4, 3, 0), >> + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_write, 2, 0), >> + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_clone, 1, 0), >> + >> + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), >> + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) >> +}; >> + >> +static const struct sock_fprog strict = { >> + .len = (unsigned short)ARRAY_SIZE(strict_filter), >> + .filter = (struct sock_filter *)strict_filter >> +}; > We do have the exact same bytecode in the prctl04.c, can we put it to a > header and include it in both tests? > > Or alternatively do we need more than just one-liner with > BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) here? we only need one-liner with BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) here. > >> static struct tcase { >> int option; >> unsigned long arg2; >> + unsigned long arg3; >> int exp_errno; >> + int bad_addr; >> } tcases[] = { >> - {OPTION_INVALID, 0, EINVAL}, >> - {PR_SET_PDEATHSIG, INVALID_ARG, EINVAL}, >> + {OPTION_INVALID, 0, 0, EINVAL, 0}, >> + {PR_SET_PDEATHSIG, INVALID_ARG, 0, EINVAL, 0}, >> + {PR_SET_DUMPABLE, 2, 0, EINVAL, 0}, >> + {PR_SET_NAME, 0, 0, EFAULT, 1}, >> + {PR_SET_SECCOMP, 2, 0, EFAULT, 1}, >> + {PR_SET_SECCOMP, 2, 2, EACCES, 0}, >> + {PR_SET_TIMING, 1, 0, EINVAL, 0}, >> +#ifdef HAVE_DECL_PR_SET_NO_NEW_PRIVS >> + {PR_SET_NO_NEW_PRIVS, 0, 0, EINVAL, 0}, >> + {PR_SET_NO_NEW_PRIVS, 1, 1, EINVAL, 0}, >> + {PR_GET_NO_NEW_PRIVS, 1, 0, EINVAL, 0}, >> +#endif >> +#ifdef HAVE_DECL_PR_SET_THP_DISABLE >> + {PR_SET_THP_DISABLE, 0, 1, EINVAL, 0}, >> + {PR_GET_THP_DISABLE, 1, 0, EINVAL, 0}, >> +#endif >> +#ifdef HAVE_DECL_PR_CAP_AMBIENT >> + {PR_CAP_AMBIENT, 2, 1, EINVAL, 0}, >> +#endif >> +#ifdef HAVE_DECL_PR_GET_SPECULATION_CTR >> + {PR_GET_SPECULATION_CTRL, 1, 0, EINVAL, 0}, >> +#endif >> + {PR_SET_SECUREBITS, 0, 0, EPERM, 0}, >> + {PR_CAPBSET_DROP, 1, 0, EPERM, 0}, >> }; >> >> static void verify_prctl(unsigned int n) >> { >> struct tcase *tc = &tcases[n]; >> >> - TEST(prctl(tc->option, tc->arg2)); >> + if (tc->arg3 == 2) >> + tc->arg3 = (unsigned long)&strict; >> + if (tc->bad_addr) { >> + if (tc->arg2) >> + tc->arg3 = (unsigned long)tst_get_bad_addr(NULL); >> + else >> + tc->arg2 = (unsigned long)tst_get_bad_addr(NULL); >> + } > I do not like this hackery, can't we just change the test to use > pointers to pointers and initialize global variables in the test setup > as we usually do? Ok. I will do it as we usually do. > >> + TEST(prctl(tc->option, tc->arg2, tc->arg3)); >> if (TST_RET == 0) { >> tst_res(TFAIL, "prctl() succeeded unexpectedly"); >> return; >> @@ -38,7 +123,10 @@ static void verify_prctl(unsigned int n) >> if (tc->exp_errno == TST_ERR) { >> tst_res(TPASS | TTERRNO, "prctl() failed as expected"); >> } else { >> - tst_res(TFAIL | TTERRNO, "prctl() failed unexpectedly, expected %s", >> + if (tc->option == PR_SET_SECCOMP && TST_ERR == EINVAL) >> + tst_res(TCONF, "current system was not built with CONFIG_SECCOMP."); >> + else >> + tst_res(TFAIL | TTERRNO, "prctl() failed unexpectedly, expected %s", >> tst_strerrno(tc->exp_errno)); >> } >> } >> @@ -46,4 +134,9 @@ static void verify_prctl(unsigned int n) >> static struct tst_test test = { >> .tcnt = ARRAY_SIZE(tcases), >> .test = verify_prctl, >> + .caps = (struct tst_cap []) { >> + TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), >> + TST_CAP(TST_CAP_DROP, CAP_SETPCAP), >> + {} >> + }, >> }; >> -- >> 2.18.0 >> >> >> >> >> -- >> Mailing list info: https://lists.linux.it/listinfo/ltp
on 2019/11/08 20:12, Yang Xu wrote: > > on 2019/11/07 22:54, Cyril Hrubis wrote: >> Hi! >>> #include <errno.h> >>> #include <signal.h> >>> #include <sys/prctl.h> >>> - >>> +#include <linux/filter.h> >>> +#include <linux/capability.h> >>> +#include <unistd.h> >>> +#include <stdlib.h> >>> +#include <stddef.h> >>> +#include "config.h" >>> +#include "lapi/prctl.h" >>> +#include "lapi/seccomp.h" >>> +#include "lapi/syscalls.h" >>> #include "tst_test.h" >>> +#include "tst_capability.h" >>> >>> #define OPTION_INVALID 999 >>> #define INVALID_ARG 999 >>> >>> +static const struct sock_filter strict_filter[] = { >>> + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof (struct seccomp_data, nr))), >>> + >>> + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_close, 5, 0), >>> + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_exit, 4, 0), >>> + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_wait4, 3, 0), >>> + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_write, 2, 0), >>> + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_clone, 1, 0), >>> + >>> + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), >>> + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) >>> +}; >>> + >>> +static const struct sock_fprog strict = { >>> + .len = (unsigned short)ARRAY_SIZE(strict_filter), >>> + .filter = (struct sock_filter *)strict_filter >>> +}; >> We do have the exact same bytecode in the prctl04.c, can we put it to a >> header and include it in both tests? >> >> Or alternatively do we need more than just one-liner with >> BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) here? > we only need one-liner with BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) here. >>> static struct tcase { >>> int option; >>> unsigned long arg2; >>> + unsigned long arg3; >>> int exp_errno; >>> + int bad_addr; >>> } tcases[] = { >>> - {OPTION_INVALID, 0, EINVAL}, >>> - {PR_SET_PDEATHSIG, INVALID_ARG, EINVAL}, >>> + {OPTION_INVALID, 0, 0, EINVAL, 0}, >>> + {PR_SET_PDEATHSIG, INVALID_ARG, 0, EINVAL, 0}, >>> + {PR_SET_DUMPABLE, 2, 0, EINVAL, 0}, >>> + {PR_SET_NAME, 0, 0, EFAULT, 1}, >>> + {PR_SET_SECCOMP, 2, 0, EFAULT, 1}, >>> + {PR_SET_SECCOMP, 2, 2, EACCES, 0}, >>> + {PR_SET_TIMING, 1, 0, EINVAL, 0}, >>> +#ifdef HAVE_DECL_PR_SET_NO_NEW_PRIVS >>> + {PR_SET_NO_NEW_PRIVS, 0, 0, EINVAL, 0}, >>> + {PR_SET_NO_NEW_PRIVS, 1, 1, EINVAL, 0}, >>> + {PR_GET_NO_NEW_PRIVS, 1, 0, EINVAL, 0}, >>> +#endif >>> +#ifdef HAVE_DECL_PR_SET_THP_DISABLE >>> + {PR_SET_THP_DISABLE, 0, 1, EINVAL, 0}, >>> + {PR_GET_THP_DISABLE, 1, 0, EINVAL, 0}, >>> +#endif >>> +#ifdef HAVE_DECL_PR_CAP_AMBIENT >>> + {PR_CAP_AMBIENT, 2, 1, EINVAL, 0}, >>> +#endif >>> +#ifdef HAVE_DECL_PR_GET_SPECULATION_CTR >>> + {PR_GET_SPECULATION_CTRL, 1, 0, EINVAL, 0}, >>> +#endif >>> + {PR_SET_SECUREBITS, 0, 0, EPERM, 0}, >>> + {PR_CAPBSET_DROP, 1, 0, EPERM, 0}, >>> }; >>> >>> static void verify_prctl(unsigned int n) >>> { >>> struct tcase *tc = &tcases[n]; >>> >>> - TEST(prctl(tc->option, tc->arg2)); >>> + if (tc->arg3 == 2) >>> + tc->arg3 = (unsigned long)&strict; >>> + if (tc->bad_addr) { >>> + if (tc->arg2) >>> + tc->arg3 = (unsigned long)tst_get_bad_addr(NULL); >>> + else >>> + tc->arg2 = (unsigned long)tst_get_bad_addr(NULL); >>> + } >> I do not like this hackery, can't we just change the test to use >> pointers to pointers and initialize global variables in the test setup >> as we usually do? > Ok. I will do it as we usually do. I think about it again. The argument of prctl is all unsigned long type. Do we need to use pointers to pointers? Or, move this code to setup function like above? >>> + TEST(prctl(tc->option, tc->arg2, tc->arg3)); >>> if (TST_RET == 0) { >>> tst_res(TFAIL, "prctl() succeeded unexpectedly"); >>> return; >>> @@ -38,7 +123,10 @@ static void verify_prctl(unsigned int n) >>> if (tc->exp_errno == TST_ERR) { >>> tst_res(TPASS | TTERRNO, "prctl() failed as expected"); >>> } else { >>> - tst_res(TFAIL | TTERRNO, "prctl() failed unexpectedly, expected %s", >>> + if (tc->option == PR_SET_SECCOMP && TST_ERR == EINVAL) >>> + tst_res(TCONF, "current system was not built with CONFIG_SECCOMP."); >>> + else >>> + tst_res(TFAIL | TTERRNO, "prctl() failed unexpectedly, expected %s", >>> tst_strerrno(tc->exp_errno)); >>> } >>> } >>> @@ -46,4 +134,9 @@ static void verify_prctl(unsigned int n) >>> static struct tst_test test = { >>> .tcnt = ARRAY_SIZE(tcases), >>> .test = verify_prctl, >>> + .caps = (struct tst_cap []) { >>> + TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), >>> + TST_CAP(TST_CAP_DROP, CAP_SETPCAP), >>> + {} >>> + }, >>> }; >>> -- >>> 2.18.0 >>> >>> >>> >>> >>> -- >>> Mailing list info:https://lists.linux.it/listinfo/ltp >
Hi! > > Ok. I will do it as we usually do. > > ??I think about it again. The argument of prctl is all unsigned long type. Do we need to use > pointers to pointers??? Or, move this code to setup function like above? Just pointer to unsigned long and do the cast in the test setup as: static unsigned long bad_addr; static struct tcase = { ... unsigned long *arg3; ... } tcases[] = { ... {..., &bad_addr, ...}, ... } static void setup(void) { invalid_addr = (unigned long)tst_get_bad_addr(); } Then call it as prctl(..., *tc->arg3).
diff --git a/include/lapi/prctl.h b/include/lapi/prctl.h index 8ee492259..ea52ecac3 100644 --- a/include/lapi/prctl.h +++ b/include/lapi/prctl.h @@ -29,6 +29,11 @@ # define PR_GET_NO_NEW_PRIVS 39 #endif +#ifndef PR_SET_THP_DISABLE +# define PR_SET_THP_DISABLE 41 +# define PR_GET_THP_DISABLE 42 +#endif + #ifndef PR_CAP_AMBIENT # define PR_CAP_AMBIENT 47 # define PR_CAP_AMBIENT_IS_SET 1 @@ -37,4 +42,9 @@ # define PR_CAP_AMBIENT_CLEAR_ALL 4 #endif +#ifndef PR_GET_SPECULATION_CTRL +# define PR_GET_SPECULATION_CTRL 52 +# define PR_SET_SPECULATION_CTRL 53 +#endif + #endif /* LAPI_PRCTL_H__ */ diff --git a/m4/ltp-prctl.m4 b/m4/ltp-prctl.m4 index e429db8fe..b592789ee 100644 --- a/m4/ltp-prctl.m4 +++ b/m4/ltp-prctl.m4 @@ -4,7 +4,8 @@ dnl Author: Ngie Cooper <yaneurabeya@gmail.com> AC_DEFUN([LTP_CHECK_PRCTL_SUPPORT],[ AC_CHECK_HEADERS(sys/prctl.h,[ - AC_CHECK_DECLS([PR_CAPBSET_DROP, PR_CAPBSET_READ], [],[],[ + AC_CHECK_DECLS([PR_CAPBSET_DROP, PR_CAPBSET_READ, PR_CAP_AMBIENT, +PR_SET_NO_NEW_PRIVS, PR_GET_SPECULATION_CTRL, PR_SET_THP_DISABLE], [],[],[ #include <sys/prctl.h> ]) dnl AC_CHECK_DECLS ])] diff --git a/testcases/kernel/syscalls/prctl/prctl02.c b/testcases/kernel/syscalls/prctl/prctl02.c index ec45911fd..2e0bbf1dc 100644 --- a/testcases/kernel/syscalls/prctl/prctl02.c +++ b/testcases/kernel/syscalls/prctl/prctl02.c @@ -4,32 +4,117 @@ * * 1) prctl() fails with EINVAL when an invalid value is given for option * 2) prctl() fails with EINVAL when option is PR_SET_PDEATHSIG & arg2 is - * not zero or a valid signal number + * not zero or a valid signal number. + * 3) prctl() fails with EINVAL when option is PR_SET_DUMPABLE & arg2 is + * neither SUID_DUMP_DISABLE nor SUID_DUMP_USER. + * 4) prctl() fails with EFAULT when arg2 is an invalid address. + * 5) prctl() fails with EFAULT when option is PR_SET_SECCOMP & arg2 is + * SECCOMP_MODE_FILTER & arg3 is an invalid address. + * 6) prctl() fails with EACCES when option is PR_SET_SECCOMP & arg2 is + * SECCOMP_MODE_FILTER & the process does not have the CAP_SYS_ADMIN + * capability. + * 7) prctl() fails with EINVAL when option is PR_SET_TIMING & arg2 is not + * not PR_TIMING_STATISTICAL. + * 8,9) prctl() fails with EINVAL when option is PR_SET_NO_NEW_PRIVS & arg2 + * is not equal to 1 or arg3 is nonzero. + * 10) prctl() fails with EINVAL when options is PR_GET_NO_NEW_PRIVS & arg2, + * arg3, arg4, or arg5 is nonzero. + * 11) prctl() fails with EINVAL when options is PR_SET_THP_DISABLE & arg3, + * arg4, arg5 is non-zero. + * 12) prctl() fails with EINVAL when options is PR_GET_THP_DISABLE & arg2, + * arg3, arg4, or arg5 is nonzero. + * 13) prctl() fails with EINVAL when options is PR_CAP_AMBIENT & an unused + * argument such as arg4 is nonzero. + * 14) prctl() fails with EINVAL when option is PR_GET_SPECULATION_CTRL and + * unused arguments is nonzero. + * 15) prctl() fails with EPERM when option is PR_SET_SECUREBITS and the + * caller does not have the CAP_SETPCAP capability. + * 16) prctl() fails with EPERM when option is PR_CAPBSET_DROP and the caller + * does not have the CAP_SETPCAP capability. */ #include <errno.h> #include <signal.h> #include <sys/prctl.h> - +#include <linux/filter.h> +#include <linux/capability.h> +#include <unistd.h> +#include <stdlib.h> +#include <stddef.h> +#include "config.h" +#include "lapi/prctl.h" +#include "lapi/seccomp.h" +#include "lapi/syscalls.h" #include "tst_test.h" +#include "tst_capability.h" #define OPTION_INVALID 999 #define INVALID_ARG 999 +static const struct sock_filter strict_filter[] = { + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof (struct seccomp_data, nr))), + + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_close, 5, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_exit, 4, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_wait4, 3, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_write, 2, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_clone, 1, 0), + + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), + BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW) +}; + +static const struct sock_fprog strict = { + .len = (unsigned short)ARRAY_SIZE(strict_filter), + .filter = (struct sock_filter *)strict_filter +}; + static struct tcase { int option; unsigned long arg2; + unsigned long arg3; int exp_errno; + int bad_addr; } tcases[] = { - {OPTION_INVALID, 0, EINVAL}, - {PR_SET_PDEATHSIG, INVALID_ARG, EINVAL}, + {OPTION_INVALID, 0, 0, EINVAL, 0}, + {PR_SET_PDEATHSIG, INVALID_ARG, 0, EINVAL, 0}, + {PR_SET_DUMPABLE, 2, 0, EINVAL, 0}, + {PR_SET_NAME, 0, 0, EFAULT, 1}, + {PR_SET_SECCOMP, 2, 0, EFAULT, 1}, + {PR_SET_SECCOMP, 2, 2, EACCES, 0}, + {PR_SET_TIMING, 1, 0, EINVAL, 0}, +#ifdef HAVE_DECL_PR_SET_NO_NEW_PRIVS + {PR_SET_NO_NEW_PRIVS, 0, 0, EINVAL, 0}, + {PR_SET_NO_NEW_PRIVS, 1, 1, EINVAL, 0}, + {PR_GET_NO_NEW_PRIVS, 1, 0, EINVAL, 0}, +#endif +#ifdef HAVE_DECL_PR_SET_THP_DISABLE + {PR_SET_THP_DISABLE, 0, 1, EINVAL, 0}, + {PR_GET_THP_DISABLE, 1, 0, EINVAL, 0}, +#endif +#ifdef HAVE_DECL_PR_CAP_AMBIENT + {PR_CAP_AMBIENT, 2, 1, EINVAL, 0}, +#endif +#ifdef HAVE_DECL_PR_GET_SPECULATION_CTR + {PR_GET_SPECULATION_CTRL, 1, 0, EINVAL, 0}, +#endif + {PR_SET_SECUREBITS, 0, 0, EPERM, 0}, + {PR_CAPBSET_DROP, 1, 0, EPERM, 0}, }; static void verify_prctl(unsigned int n) { struct tcase *tc = &tcases[n]; - TEST(prctl(tc->option, tc->arg2)); + if (tc->arg3 == 2) + tc->arg3 = (unsigned long)&strict; + if (tc->bad_addr) { + if (tc->arg2) + tc->arg3 = (unsigned long)tst_get_bad_addr(NULL); + else + tc->arg2 = (unsigned long)tst_get_bad_addr(NULL); + } + TEST(prctl(tc->option, tc->arg2, tc->arg3)); if (TST_RET == 0) { tst_res(TFAIL, "prctl() succeeded unexpectedly"); return; @@ -38,7 +123,10 @@ static void verify_prctl(unsigned int n) if (tc->exp_errno == TST_ERR) { tst_res(TPASS | TTERRNO, "prctl() failed as expected"); } else { - tst_res(TFAIL | TTERRNO, "prctl() failed unexpectedly, expected %s", + if (tc->option == PR_SET_SECCOMP && TST_ERR == EINVAL) + tst_res(TCONF, "current system was not built with CONFIG_SECCOMP."); + else + tst_res(TFAIL | TTERRNO, "prctl() failed unexpectedly, expected %s", tst_strerrno(tc->exp_errno)); } } @@ -46,4 +134,9 @@ static void verify_prctl(unsigned int n) static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .test = verify_prctl, + .caps = (struct tst_cap []) { + TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), + TST_CAP(TST_CAP_DROP, CAP_SETPCAP), + {} + }, };
------ v2->v3: 1.add missing <linux/capability.h> ------ Signed-off-by: Yang Xu <xuyang2018.jy@cn.fujitsu.com> --- include/lapi/prctl.h | 10 +++ m4/ltp-prctl.m4 | 3 +- testcases/kernel/syscalls/prctl/prctl02.c | 105 ++++++++++++++++++++-- 3 files changed, 111 insertions(+), 7 deletions(-)