Message ID | 20181206150156.28210-3-david.abdurachmanov@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | riscv: add support for SECCOMP and SECCOMP_FILTER | expand |
On Thu, Dec 6, 2018 at 7:02 AM David Abdurachmanov <david.abdurachmanov@gmail.com> wrote: > > Testing with libseccomp master branch revealed that testcases with > filters on syscall arguments were failing due to wrong values. Seccomp > uses syscall_get_argumentsi() to copy syscall arguments, and there is a > bug in pointer arithmetics in memcpy() call. > > Two alternative implementation were tested: the one in this patch and > another one based on while-break loop. Both delivered the same results. > > This implementation is also used in arm, arm64 and nds32 arches. Minor nit: can you make this the first patch? That way seccomp works correctly from the point of introduction. :) -Kees > > Signed-off-by: David Abdurachmanov <david.abdurachmanov@gmail.com> > --- > arch/riscv/include/asm/syscall.h | 42 ++++++++++++++++++++++++-------- > 1 file changed, 32 insertions(+), 10 deletions(-) > > diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h > index bba3da6ef157..26ceb434a433 100644 > --- a/arch/riscv/include/asm/syscall.h > +++ b/arch/riscv/include/asm/syscall.h > @@ -70,19 +70,32 @@ static inline void syscall_set_return_value(struct task_struct *task, > regs->a0 = (long) error ?: val; > } > > +#define SYSCALL_MAX_ARGS 6 > + > static inline void syscall_get_arguments(struct task_struct *task, > struct pt_regs *regs, > unsigned int i, unsigned int n, > unsigned long *args) > { > - BUG_ON(i + n > 6); > + if (n == 0) > + return; > + > + if (i + n > SYSCALL_MAX_ARGS) { > + unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i; > + unsigned int n_bad = n + i - SYSCALL_MAX_ARGS; > + pr_warning("%s called with max args %d, handling only %d\n", > + __func__, i + n, SYSCALL_MAX_ARGS); > + memset(args_bad, 0, n_bad * sizeof(args[0])); > + } > + > if (i == 0) { > args[0] = regs->orig_a0; > args++; > i++; > n--; > } > - memcpy(args, ®s->a1 + i * sizeof(regs->a1), n * sizeof(args[0])); > + > + memcpy(args, ®s->a0 + i, n * sizeof(args[0])); > } > > static inline void syscall_set_arguments(struct task_struct *task, > @@ -90,14 +103,23 @@ static inline void syscall_set_arguments(struct task_struct *task, > unsigned int i, unsigned int n, > const unsigned long *args) > { > - BUG_ON(i + n > 6); > - if (i == 0) { > - regs->orig_a0 = args[0]; > - args++; > - i++; > - n--; > - } > - memcpy(®s->a1 + i * sizeof(regs->a1), args, n * sizeof(regs->a0)); > + if (n == 0) > + return; > + > + if (i + n > SYSCALL_MAX_ARGS) { > + pr_warning("%s called with max args %d, handling only %d\n", > + __func__, i + n, SYSCALL_MAX_ARGS); > + n = SYSCALL_MAX_ARGS - i; > + } > + > + if (i == 0) { > + regs->orig_a0 = args[0]; > + args++; > + i++; > + n--; > + } > + > + memcpy(®s->a0 + i, args, n * sizeof(args[0])); > } > > static inline int syscall_get_arch(void) > -- > 2.19.2 >
On Thu, Dec 6, 2018 at 5:49 PM Kees Cook <keescook@chromium.org> wrote: > > On Thu, Dec 6, 2018 at 7:02 AM David Abdurachmanov > <david.abdurachmanov@gmail.com> wrote: > > > > Testing with libseccomp master branch revealed that testcases with > > filters on syscall arguments were failing due to wrong values. Seccomp > > uses syscall_get_argumentsi() to copy syscall arguments, and there is a > > bug in pointer arithmetics in memcpy() call. > > > > Two alternative implementation were tested: the one in this patch and > > another one based on while-break loop. Both delivered the same results. > > > > This implementation is also used in arm, arm64 and nds32 arches. > > Minor nit: can you make this the first patch? That way seccomp works > correctly from the point of introduction. :) Ok. I will do it. david > > -Kees > > > > > Signed-off-by: David Abdurachmanov <david.abdurachmanov@gmail.com> > > --- > > arch/riscv/include/asm/syscall.h | 42 ++++++++++++++++++++++++-------- > > 1 file changed, 32 insertions(+), 10 deletions(-) > > > > diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h > > index bba3da6ef157..26ceb434a433 100644 > > --- a/arch/riscv/include/asm/syscall.h > > +++ b/arch/riscv/include/asm/syscall.h > > @@ -70,19 +70,32 @@ static inline void syscall_set_return_value(struct task_struct *task, > > regs->a0 = (long) error ?: val; > > } > > > > +#define SYSCALL_MAX_ARGS 6 > > + > > static inline void syscall_get_arguments(struct task_struct *task, > > struct pt_regs *regs, > > unsigned int i, unsigned int n, > > unsigned long *args) > > { > > - BUG_ON(i + n > 6); > > + if (n == 0) > > + return; > > + > > + if (i + n > SYSCALL_MAX_ARGS) { > > + unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i; > > + unsigned int n_bad = n + i - SYSCALL_MAX_ARGS; > > + pr_warning("%s called with max args %d, handling only %d\n", > > + __func__, i + n, SYSCALL_MAX_ARGS); > > + memset(args_bad, 0, n_bad * sizeof(args[0])); > > + } > > + > > if (i == 0) { > > args[0] = regs->orig_a0; > > args++; > > i++; > > n--; > > } > > - memcpy(args, ®s->a1 + i * sizeof(regs->a1), n * sizeof(args[0])); > > + > > + memcpy(args, ®s->a0 + i, n * sizeof(args[0])); > > } > > > > static inline void syscall_set_arguments(struct task_struct *task, > > @@ -90,14 +103,23 @@ static inline void syscall_set_arguments(struct task_struct *task, > > unsigned int i, unsigned int n, > > const unsigned long *args) > > { > > - BUG_ON(i + n > 6); > > - if (i == 0) { > > - regs->orig_a0 = args[0]; > > - args++; > > - i++; > > - n--; > > - } > > - memcpy(®s->a1 + i * sizeof(regs->a1), args, n * sizeof(regs->a0)); > > + if (n == 0) > > + return; > > + > > + if (i + n > SYSCALL_MAX_ARGS) { > > + pr_warning("%s called with max args %d, handling only %d\n", > > + __func__, i + n, SYSCALL_MAX_ARGS); > > + n = SYSCALL_MAX_ARGS - i; > > + } > > + > > + if (i == 0) { > > + regs->orig_a0 = args[0]; > > + args++; > > + i++; > > + n--; > > + } > > + > > + memcpy(®s->a0 + i, args, n * sizeof(args[0])); > > } > > > > static inline int syscall_get_arch(void) > > -- > > 2.19.2 > > > > > -- > Kees Cook
diff --git a/arch/riscv/include/asm/syscall.h b/arch/riscv/include/asm/syscall.h index bba3da6ef157..26ceb434a433 100644 --- a/arch/riscv/include/asm/syscall.h +++ b/arch/riscv/include/asm/syscall.h @@ -70,19 +70,32 @@ static inline void syscall_set_return_value(struct task_struct *task, regs->a0 = (long) error ?: val; } +#define SYSCALL_MAX_ARGS 6 + static inline void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, unsigned int i, unsigned int n, unsigned long *args) { - BUG_ON(i + n > 6); + if (n == 0) + return; + + if (i + n > SYSCALL_MAX_ARGS) { + unsigned long *args_bad = args + SYSCALL_MAX_ARGS - i; + unsigned int n_bad = n + i - SYSCALL_MAX_ARGS; + pr_warning("%s called with max args %d, handling only %d\n", + __func__, i + n, SYSCALL_MAX_ARGS); + memset(args_bad, 0, n_bad * sizeof(args[0])); + } + if (i == 0) { args[0] = regs->orig_a0; args++; i++; n--; } - memcpy(args, ®s->a1 + i * sizeof(regs->a1), n * sizeof(args[0])); + + memcpy(args, ®s->a0 + i, n * sizeof(args[0])); } static inline void syscall_set_arguments(struct task_struct *task, @@ -90,14 +103,23 @@ static inline void syscall_set_arguments(struct task_struct *task, unsigned int i, unsigned int n, const unsigned long *args) { - BUG_ON(i + n > 6); - if (i == 0) { - regs->orig_a0 = args[0]; - args++; - i++; - n--; - } - memcpy(®s->a1 + i * sizeof(regs->a1), args, n * sizeof(regs->a0)); + if (n == 0) + return; + + if (i + n > SYSCALL_MAX_ARGS) { + pr_warning("%s called with max args %d, handling only %d\n", + __func__, i + n, SYSCALL_MAX_ARGS); + n = SYSCALL_MAX_ARGS - i; + } + + if (i == 0) { + regs->orig_a0 = args[0]; + args++; + i++; + n--; + } + + memcpy(®s->a0 + i, args, n * sizeof(args[0])); } static inline int syscall_get_arch(void)
Testing with libseccomp master branch revealed that testcases with filters on syscall arguments were failing due to wrong values. Seccomp uses syscall_get_argumentsi() to copy syscall arguments, and there is a bug in pointer arithmetics in memcpy() call. Two alternative implementation were tested: the one in this patch and another one based on while-break loop. Both delivered the same results. This implementation is also used in arm, arm64 and nds32 arches. Signed-off-by: David Abdurachmanov <david.abdurachmanov@gmail.com> --- arch/riscv/include/asm/syscall.h | 42 ++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 10 deletions(-)