2009-01-06 03:06:46

by Hiroshi Shimamoto

[permalink] [raw]
Subject: [RFC -tip 0/4] x86: reduce fixup of uaccess

This is my second try to reduce fixup code size for exceptions of uaccess.

This patch series reduces fixup code for exceptions of uaccess in signal.

I gave up to make direct jump to end of function when an exception occurs.
However, I thought fixup code could be reduced. The concept is that to add
uaccess_err in thread_info and set it to -EFAULT on exception, finally check
this value on the last of function.

Is this good to reduce code size?

The code size reductions are below;
$ size *signal*.o.*
text data bss dec hex filename
4741 0 0 4741 1285 ia32_signal.o.new
6006 0 0 6006 1776 ia32_signal.o.old
3577 0 0 3577 df9 signal.o.new
4540 0 0 4540 11bc signal.o.old
3855 0 0 3855 f0f signal32.o.new
4876 0 0 4876 130c signal32.o.old

Thanks,
Hiroshi


2009-01-06 03:08:30

by Hiroshi Shimamoto

[permalink] [raw]
Subject: [RFC -tip 1/4] x86: uaccess: rename __put_user_u64() to __put_user_asm_u64()

From: Hiroshi Shimamoto <[email protected]>

Impact: cleanup

Rename __put_user_u64() to __put_user_asm_u64() like __get_user_asm_u64().

Signed-off-by: Hiroshi Shimamoto <[email protected]>
---
arch/x86/include/asm/uaccess.h | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 4340055..1a38180 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -186,7 +186,7 @@ extern int __get_user_bad(void);


#ifdef CONFIG_X86_32
-#define __put_user_u64(x, addr, err) \
+#define __put_user_asm_u64(x, addr, err) \
asm volatile("1: movl %%eax,0(%2)\n" \
"2: movl %%edx,4(%2)\n" \
"3:\n" \
@@ -203,7 +203,7 @@ extern int __get_user_bad(void);
asm volatile("call __put_user_8" : "=a" (__ret_pu) \
: "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
#else
-#define __put_user_u64(x, ptr, retval) \
+#define __put_user_asm_u64(x, ptr, retval) \
__put_user_asm(x, ptr, retval, "q", "", "Zr", -EFAULT)
#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
#endif
@@ -279,7 +279,7 @@ do { \
__put_user_asm(x, ptr, retval, "l", "k", "ir", errret);\
break; \
case 8: \
- __put_user_u64((__typeof__(*ptr))(x), ptr, retval); \
+ __put_user_asm_u64((__typeof__(*ptr))(x), ptr, retval); \
break; \
default: \
__put_user_bad(); \
--
1.6.0.4

2009-01-06 03:09:18

by Hiroshi Shimamoto

[permalink] [raw]
Subject: [RFC -tip 2/4] x86: uaccess: introduce new __{get|put}_user exception handling framework

From: Hiroshi Shimamoto <[email protected]>

Impact: introduce new uaccess exception handling framework

Introduce new uaccess exception handling framework.

__{get|put}_user_ex_try() begins exception block and
__{get|put}_user_ex_catch() ends block and if an exeption occurred in this
block using __{get|put}_user_ex, thread_info->uaccess_err is set to -EFAULT
and err is set at __{get|put}_user_ex_catch().

int func()
{
int err = 0;

__get_user_ex_try();

__get_user_ex(...);
__get_user_ex(...);
:

__get_user_ex_catch(&err);
return err;
}

Note: __get_user_ex() is not clear the value when an exception occurs, it's
different from the behavior of __get_user(), but I think it doesn't matter.

Signed-off-by: Hiroshi Shimamoto <[email protected]>
---
arch/x86/include/asm/thread_info.h | 1 +
arch/x86/include/asm/uaccess.h | 100 ++++++++++++++++++++++++++++++++++++
arch/x86/mm/extable.c | 5 ++
3 files changed, 106 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index efdf938..46beb17 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -40,6 +40,7 @@ struct thread_info {
*/
__u8 supervisor_stack[0];
#endif
+ int uaccess_err;
};

#define INIT_THREAD_INFO(tsk) \
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 1a38180..d3ac43e 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -199,12 +199,22 @@ extern int __get_user_bad(void);
: "=r" (err) \
: "A" (x), "r" (addr), "i" (-EFAULT), "0" (err))

+#define __put_user_asm_ex_u64(x, addr) \
+ asm volatile("1: movl %%eax,0(%1)\n" \
+ "2: movl %%edx,4(%1)\n" \
+ "3:\n" \
+ _ASM_EXTABLE(1b, 2b - 1b) \
+ _ASM_EXTABLE(2b, 3b - 2b) \
+ : : "A" (x), "r" (addr))
+
#define __put_user_x8(x, ptr, __ret_pu) \
asm volatile("call __put_user_8" : "=a" (__ret_pu) \
: "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
#else
#define __put_user_asm_u64(x, ptr, retval) \
__put_user_asm(x, ptr, retval, "q", "", "Zr", -EFAULT)
+#define __put_user_asm_ex_u64(x, addr) \
+ __put_user_asm_ex(x, addr, "q", "", "Zr")
#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
#endif

@@ -286,6 +296,27 @@ do { \
} \
} while (0)

+#define __put_user_size_ex(x, ptr, size) \
+do { \
+ __chk_user_ptr(ptr); \
+ switch (size) { \
+ case 1: \
+ __put_user_asm_ex(x, ptr, "b", "b", "iq"); \
+ break; \
+ case 2: \
+ __put_user_asm_ex(x, ptr, "w", "w", "ir"); \
+ break; \
+ case 4: \
+ __put_user_asm_ex(x, ptr, "l", "k", "ir"); \
+ break; \
+ case 8: \
+ __put_user_asm_ex_u64((__typeof__(*ptr))(x), ptr); \
+ break; \
+ default: \
+ __put_user_bad(); \
+ } \
+} while (0)
+
#else

#define __put_user_size(x, ptr, size, retval, errret) \
@@ -311,9 +342,12 @@ do { \

#ifdef CONFIG_X86_32
#define __get_user_asm_u64(x, ptr, retval, errret) (x) = __get_user_bad()
+#define __get_user_asm_ex_u64(x, ptr) (x) = __get_user_bad()
#else
#define __get_user_asm_u64(x, ptr, retval, errret) \
__get_user_asm(x, ptr, retval, "q", "", "=r", errret)
+#define __get_user_asm_ex_u64(x, ptr) \
+ __get_user_asm_ex(x, ptr, "q", "", "=r")
#endif

#define __get_user_size(x, ptr, size, retval, errret) \
@@ -350,6 +384,33 @@ do { \
: "=r" (err), ltype(x) \
: "m" (__m(addr)), "i" (errret), "0" (err))

+#define __get_user_size_ex(x, ptr, size) \
+do { \
+ __chk_user_ptr(ptr); \
+ switch (size) { \
+ case 1: \
+ __get_user_asm_ex(x, ptr, "b", "b", "=q"); \
+ break; \
+ case 2: \
+ __get_user_asm_ex(x, ptr, "w", "w", "=r"); \
+ break; \
+ case 4: \
+ __get_user_asm_ex(x, ptr, "l", "k", "=r"); \
+ break; \
+ case 8: \
+ __get_user_asm_ex_u64(x, ptr); \
+ break; \
+ default: \
+ (x) = __get_user_bad(); \
+ } \
+} while (0)
+
+#define __get_user_asm_ex(x, addr, itype, rtype, ltype) \
+ asm volatile("1: mov"itype" %1,%"rtype"0\n" \
+ "2:\n" \
+ _ASM_EXTABLE(1b, 2b - 1b) \
+ : ltype(x) : "m" (__m(addr)))
+
#define __put_user_nocheck(x, ptr, size) \
({ \
int __pu_err; \
@@ -385,6 +446,23 @@ struct __large_struct { unsigned long buf[100]; };
_ASM_EXTABLE(1b, 3b) \
: "=r"(err) \
: ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
+
+#define __put_user_asm_ex(x, addr, itype, rtype, ltype) \
+ asm volatile("1: mov"itype" %"rtype"0,%1\n" \
+ "2:\n" \
+ _ASM_EXTABLE(1b, 2b - 1b) \
+ : : ltype(x), "m" (__m(addr)))
+
+#define __uaccess_ex_try() do { \
+ int __prev_err = current_thread_info()->uaccess_err; \
+ current_thread_info()->uaccess_err = 0; \
+ barrier()
+
+#define __uaccess_ex_catch(err) \
+ (err) |= current_thread_info()->uaccess_err; \
+ current_thread_info()->uaccess_err = __prev_err; \
+} while (0)
+
/**
* __get_user: - Get a simple variable from user space, with less checking.
* @x: Variable to store result.
@@ -408,6 +486,19 @@ struct __large_struct { unsigned long buf[100]; };

#define __get_user(x, ptr) \
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
+
+#define __get_user_ex(x, ptr) do { \
+ unsigned long __gue_val; \
+ __get_user_size_ex((__gue_val), (ptr), (sizeof(*(ptr)))); \
+ (x) = (__force __typeof__(*(ptr)))__gue_val; \
+} while (0)
+
+#define __get_user_ex_try() \
+ __uaccess_ex_try()
+
+#define __get_user_ex_catch(perr) \
+ __uaccess_ex_catch(*(perr))
+
/**
* __put_user: - Write a simple value into user space, with less checking.
* @x: Value to copy to user space.
@@ -431,6 +522,15 @@ struct __large_struct { unsigned long buf[100]; };
#define __put_user(x, ptr) \
__put_user_nocheck((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))

+#define __put_user_ex(x, ptr) \
+ __put_user_size_ex((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+
+#define __put_user_ex_try() \
+ __uaccess_ex_try()
+
+#define __put_user_ex_catch(perr) \
+ __uaccess_ex_catch(*(perr))
+
#define __get_user_unaligned __get_user
#define __put_user_unaligned __put_user

diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 7e8db53..e185e03 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -23,6 +23,11 @@ int fixup_exception(struct pt_regs *regs)

fixup = search_exception_tables(regs->ip);
if (fixup) {
+ if (fixup->fixup < 16) {
+ current_thread_info()->uaccess_err = -EFAULT;
+ regs->ip += fixup->fixup;
+ return 1;
+ }
regs->ip = fixup->fixup;
return 1;
}
--
1.6.0.4

2009-01-06 03:09:45

by Hiroshi Shimamoto

[permalink] [raw]
Subject: [RFC -tip 3/4] x86: signal: use __{get|put}_user_ex exception handling framework

From: Hiroshi Shimamoto <[email protected]>

Impact: use new uaccess exception handling framework

Use __{get|put}_user_ex exception handling framework.

Signed-off-by: Hiroshi Shimamoto <[email protected]>
---
arch/x86/kernel/signal.c | 214 +++++++++++++++++++++++++---------------------
1 files changed, 118 insertions(+), 96 deletions(-)

diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 4fa5243..0927549 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -51,24 +51,24 @@
#endif

#define COPY(x) { \
- err |= __get_user(regs->x, &sc->x); \
+ __get_user_ex(regs->x, &sc->x); \
}

#define COPY_SEG(seg) { \
unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
+ __get_user_ex(tmp, &sc->seg); \
regs->seg = tmp; \
}

#define COPY_SEG_CPL3(seg) { \
unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
+ __get_user_ex(tmp, &sc->seg); \
regs->seg = tmp | 3; \
}

#define GET_SEG(seg) { \
unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
+ __get_user_ex(tmp, &sc->seg); \
loadsegment(seg, tmp); \
}

@@ -83,6 +83,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;

+ __get_user_ex_try();
+
#ifdef CONFIG_X86_32
GET_SEG(gs);
COPY_SEG(fs);
@@ -114,14 +116,16 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
COPY_SEG_CPL3(cs);
#endif /* CONFIG_X86_32 */

- err |= __get_user(tmpflags, &sc->flags);
+ __get_user_ex(tmpflags, &sc->flags);
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
regs->orig_ax = -1; /* disable syscall checks */

- err |= __get_user(buf, &sc->fpstate);
+ __get_user_ex(buf, &sc->fpstate);
err |= restore_i387_xstate(buf);

- err |= __get_user(*pax, &sc->ax);
+ __get_user_ex(*pax, &sc->ax);
+
+ __get_user_ex_catch(&err);
return err;
}

@@ -131,57 +135,61 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
{
int err = 0;

+ __put_user_ex_try();
+
#ifdef CONFIG_X86_32
{
unsigned int tmp;

savesegment(gs, tmp);
- err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
+ __put_user_ex(tmp, (unsigned int __user *)&sc->gs);
}
- err |= __put_user(regs->fs, (unsigned int __user *)&sc->fs);
- err |= __put_user(regs->es, (unsigned int __user *)&sc->es);
- err |= __put_user(regs->ds, (unsigned int __user *)&sc->ds);
+ __put_user_ex(regs->fs, (unsigned int __user *)&sc->fs);
+ __put_user_ex(regs->es, (unsigned int __user *)&sc->es);
+ __put_user_ex(regs->ds, (unsigned int __user *)&sc->ds);
#endif /* CONFIG_X86_32 */

- err |= __put_user(regs->di, &sc->di);
- err |= __put_user(regs->si, &sc->si);
- err |= __put_user(regs->bp, &sc->bp);
- err |= __put_user(regs->sp, &sc->sp);
- err |= __put_user(regs->bx, &sc->bx);
- err |= __put_user(regs->dx, &sc->dx);
- err |= __put_user(regs->cx, &sc->cx);
- err |= __put_user(regs->ax, &sc->ax);
+ __put_user_ex(regs->di, &sc->di);
+ __put_user_ex(regs->si, &sc->si);
+ __put_user_ex(regs->bp, &sc->bp);
+ __put_user_ex(regs->sp, &sc->sp);
+ __put_user_ex(regs->bx, &sc->bx);
+ __put_user_ex(regs->dx, &sc->dx);
+ __put_user_ex(regs->cx, &sc->cx);
+ __put_user_ex(regs->ax, &sc->ax);
#ifdef CONFIG_X86_64
- err |= __put_user(regs->r8, &sc->r8);
- err |= __put_user(regs->r9, &sc->r9);
- err |= __put_user(regs->r10, &sc->r10);
- err |= __put_user(regs->r11, &sc->r11);
- err |= __put_user(regs->r12, &sc->r12);
- err |= __put_user(regs->r13, &sc->r13);
- err |= __put_user(regs->r14, &sc->r14);
- err |= __put_user(regs->r15, &sc->r15);
+ __put_user_ex(regs->r8, &sc->r8);
+ __put_user_ex(regs->r9, &sc->r9);
+ __put_user_ex(regs->r10, &sc->r10);
+ __put_user_ex(regs->r11, &sc->r11);
+ __put_user_ex(regs->r12, &sc->r12);
+ __put_user_ex(regs->r13, &sc->r13);
+ __put_user_ex(regs->r14, &sc->r14);
+ __put_user_ex(regs->r15, &sc->r15);
#endif /* CONFIG_X86_64 */

- err |= __put_user(current->thread.trap_no, &sc->trapno);
- err |= __put_user(current->thread.error_code, &sc->err);
- err |= __put_user(regs->ip, &sc->ip);
+ __put_user_ex(current->thread.trap_no, &sc->trapno);
+ __put_user_ex(current->thread.error_code, &sc->err);
+ __put_user_ex(regs->ip, &sc->ip);
#ifdef CONFIG_X86_32
- err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs);
- err |= __put_user(regs->flags, &sc->flags);
- err |= __put_user(regs->sp, &sc->sp_at_signal);
- err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
+ __put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
+ __put_user_ex(regs->flags, &sc->flags);
+ __put_user_ex(regs->sp, &sc->sp_at_signal);
+ __put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
#else /* !CONFIG_X86_32 */
- err |= __put_user(regs->flags, &sc->flags);
- err |= __put_user(regs->cs, &sc->cs);
- err |= __put_user(0, &sc->gs);
- err |= __put_user(0, &sc->fs);
+ __put_user_ex(regs->flags, &sc->flags);
+ __put_user_ex(regs->cs, &sc->cs);
+ __put_user_ex(0, &sc->gs);
+ __put_user_ex(0, &sc->fs);
#endif /* CONFIG_X86_32 */

- err |= __put_user(fpstate, &sc->fpstate);
+ __put_user_ex(fpstate, &sc->fpstate);

/* non-iBCS2 extensions.. */
- err |= __put_user(mask, &sc->oldmask);
- err |= __put_user(current->thread.cr2, &sc->cr2);
+ __put_user_ex(mask, &sc->oldmask);
+ __put_user_ex(current->thread.cr2, &sc->cr2);
+
+ __put_user_ex_catch(&err);

return err;
}
@@ -274,16 +282,19 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;

- if (__put_user(sig, &frame->sig))
- return -EFAULT;
+ __put_user_ex_try();

- if (setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
- return -EFAULT;
+ __put_user_ex(sig, &frame->sig);
+
+ err |= setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
+ if (err)
+ goto out;

if (_NSIG_WORDS > 1) {
- if (__copy_to_user(&frame->extramask, &set->sig[1],
- sizeof(frame->extramask)))
- return -EFAULT;
+ err |= __copy_to_user(&frame->extramask, &set->sig[1],
+ sizeof(frame->extramask));
+ if (err)
+ goto out;
}

if (current->mm->context.vdso)
@@ -294,7 +305,7 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
restorer = ka->sa.sa_restorer;

/* Set up to return from userspace. */
- err |= __put_user(restorer, &frame->pretcode);
+ __put_user_ex(restorer, &frame->pretcode);

/*
* This is popl %eax ; movl $__NR_sigreturn, %eax ; int $0x80
@@ -303,10 +314,7 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
* reasons and because gdb uses it as a signature to notice
* signal handler stack frames.
*/
- err |= __put_user(*((u64 *)&retcode), (u64 *)frame->retcode);
-
- if (err)
- return -EFAULT;
+ __put_user_ex(*((u64 *)&retcode), (u64 *)frame->retcode);

/* Set up registers for signal handler */
regs->sp = (unsigned long)frame;
@@ -320,7 +328,10 @@ __setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
regs->ss = __USER_DS;
regs->cs = __USER_CS;

- return 0;
+out:
+ __put_user_ex_catch(&err);
+
+ return err;
}

static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -336,34 +347,36 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;

- err |= __put_user(sig, &frame->sig);
- err |= __put_user(&frame->info, &frame->pinfo);
- err |= __put_user(&frame->uc, &frame->puc);
+ __put_user_ex_try();
+
+ __put_user_ex(sig, &frame->sig);
+ __put_user_ex(&frame->info, &frame->pinfo);
+ __put_user_ex(&frame->uc, &frame->puc);
err |= copy_siginfo_to_user(&frame->info, info);
if (err)
- return -EFAULT;
+ goto out;

/* Create the ucontext. */
if (cpu_has_xsave)
- err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
+ __put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
else
- err |= __put_user(0, &frame->uc.uc_flags);
- err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->sp),
+ __put_user_ex(0, &frame->uc.uc_flags);
+ __put_user_ex(0, &frame->uc.uc_link);
+ __put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ __put_user_ex(sas_ss_flags(regs->sp),
&frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ __put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
- return -EFAULT;
+ goto out;

/* Set up to return from userspace. */
restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
if (ka->sa.sa_flags & SA_RESTORER)
restorer = ka->sa.sa_restorer;
- err |= __put_user(restorer, &frame->pretcode);
+ __put_user_ex(restorer, &frame->pretcode);

/*
* This is movl $__NR_rt_sigreturn, %ax ; int $0x80
@@ -372,10 +385,7 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
* reasons and because gdb uses it as a signature to notice
* signal handler stack frames.
*/
- err |= __put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
-
- if (err)
- return -EFAULT;
+ __put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);

/* Set up registers for signal handler */
regs->sp = (unsigned long)frame;
@@ -389,7 +399,10 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
regs->ss = __USER_DS;
regs->cs = __USER_CS;

- return 0;
+out:
+ __put_user_ex_catch(&err);
+
+ return err;
}
#else /* !CONFIG_X86_32 */
/*
@@ -436,16 +449,18 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return -EFAULT;
}

+ __put_user_ex_try();
+
/* Create the ucontext. */
if (cpu_has_xsave)
- err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
+ __put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
else
- err |= __put_user(0, &frame->uc.uc_flags);
- err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->sp),
+ __put_user_ex(0, &frame->uc.uc_flags);
+ __put_user_ex(0, &frame->uc.uc_link);
+ __put_user_ex(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ __put_user_ex(sas_ss_flags(regs->sp),
&frame->uc.uc_stack.ss_flags);
- err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ __put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));

@@ -453,15 +468,13 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
already in userspace. */
/* x86-64 should always use SA_RESTORER. */
if (ka->sa.sa_flags & SA_RESTORER) {
- err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
+ __put_user_ex(ka->sa.sa_restorer, &frame->pretcode);
} else {
/* could use a vstub here */
- return -EFAULT;
+ err = -EFAULT;
+ goto out;
}

- if (err)
- return -EFAULT;
-
/* Set up registers for signal handler */
regs->di = sig;
/* In case the signal handler was declared without prototypes */
@@ -479,7 +492,10 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
even if the handler happens to be interrupting 32-bit code. */
regs->cs = __USER_CS;

- return 0;
+out:
+ __put_user_ex_catch(&err);
+
+ return err;
}
#endif /* CONFIG_X86_32 */

@@ -509,31 +525,37 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
struct old_sigaction __user *oact)
{
struct k_sigaction new_ka, old_ka;
- int ret;
+ int ret = 0;

if (act) {
old_sigset_t mask;

- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ if (!access_ok(VERIFY_READ, act, sizeof(*act)))
+ return -EFAULT;
+ __get_user_ex_try();
+ __get_user_ex(new_ka.sa.sa_handler, &act->sa_handler);
+ __get_user_ex(new_ka.sa.sa_flags, &act->sa_flags);
+ __get_user_ex(mask, &act->sa_mask);
+ __get_user_ex(new_ka.sa.sa_restorer, &act->sa_restorer);
+ __get_user_ex_catch(&ret);
+ if (ret)
return -EFAULT;
-
- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
siginitset(&new_ka.sa.sa_mask, mask);
}

ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);

if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
+ return -EFAULT;
+ __put_user_ex_try();
+ __put_user_ex(old_ka.sa.sa_handler, &oact->sa_handler);
+ __put_user_ex(old_ka.sa.sa_flags, &oact->sa_flags);
+ __put_user_ex(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ __put_user_ex(old_ka.sa.sa_restorer, &oact->sa_restorer);
+ __put_user_ex_catch(&ret);
+ if (ret)
return -EFAULT;
-
- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
}

return ret;
--
1.6.0.4

2009-01-06 03:10:27

by Hiroshi Shimamoto

[permalink] [raw]
Subject: [RFC -tip 4/4] x86: ia32_signal: use __{get|put}_user_ex exception handling framework

From: Hiroshi Shimamoto <[email protected]>

Impact: use new uaccess exception handling framework

Use __{get|put}_user_ex exception handling framework.

Signed-off-by: Hiroshi Shimamoto <[email protected]>
---
arch/x86/ia32/ia32_signal.c | 220 +++++++++++++++++++++++++------------------
1 files changed, 127 insertions(+), 93 deletions(-)

diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 9dabd00..9502a77 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -46,79 +46,88 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where);

int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
{
- int err;
+ int err = 0;

if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
return -EFAULT;

+ __put_user_ex_try();
+
/* If you change siginfo_t structure, please make sure that
this code is fixed accordingly.
It should never copy any pad contained in the structure
to avoid security leaks, but must copy the generic
3 ints plus the relevant union member. */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user((short)from->si_code, &to->si_code);
+ __put_user_ex(from->si_signo, &to->si_signo);
+ __put_user_ex(from->si_errno, &to->si_errno);
+ __put_user_ex((short)from->si_code, &to->si_code);

if (from->si_code < 0) {
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
+ __put_user_ex(from->si_pid, &to->si_pid);
+ __put_user_ex(from->si_uid, &to->si_uid);
+ __put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
} else {
/*
* First 32bits of unions are always present:
* si_pid === si_band === si_tid === si_addr(LS half)
*/
- err |= __put_user(from->_sifields._pad[0],
+ __put_user_ex(from->_sifields._pad[0],
&to->_sifields._pad[0]);
switch (from->si_code >> 16) {
case __SI_FAULT >> 16:
break;
case __SI_CHLD >> 16:
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- err |= __put_user(from->si_status, &to->si_status);
+ __put_user_ex(from->si_utime, &to->si_utime);
+ __put_user_ex(from->si_stime, &to->si_stime);
+ __put_user_ex(from->si_status, &to->si_status);
/* FALL THROUGH */
default:
case __SI_KILL >> 16:
- err |= __put_user(from->si_uid, &to->si_uid);
+ __put_user_ex(from->si_uid, &to->si_uid);
break;
case __SI_POLL >> 16:
- err |= __put_user(from->si_fd, &to->si_fd);
+ __put_user_ex(from->si_fd, &to->si_fd);
break;
case __SI_TIMER >> 16:
- err |= __put_user(from->si_overrun, &to->si_overrun);
- err |= __put_user(ptr_to_compat(from->si_ptr),
+ __put_user_ex(from->si_overrun, &to->si_overrun);
+ __put_user_ex(ptr_to_compat(from->si_ptr),
&to->si_ptr);
break;
/* This is not generated by the kernel as of now. */
case __SI_RT >> 16:
case __SI_MESGQ >> 16:
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_int, &to->si_int);
+ __put_user_ex(from->si_uid, &to->si_uid);
+ __put_user_ex(from->si_int, &to->si_int);
break;
}
}
+
+ __put_user_ex_catch(&err);
+
return err;
}

int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
{
- int err;
+ int err = 0;
u32 ptr32;

if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
return -EFAULT;

- err = __get_user(to->si_signo, &from->si_signo);
- err |= __get_user(to->si_errno, &from->si_errno);
- err |= __get_user(to->si_code, &from->si_code);
+ __get_user_ex_try();

- err |= __get_user(to->si_pid, &from->si_pid);
- err |= __get_user(to->si_uid, &from->si_uid);
- err |= __get_user(ptr32, &from->si_ptr);
+ __get_user_ex(to->si_signo, &from->si_signo);
+ __get_user_ex(to->si_errno, &from->si_errno);
+ __get_user_ex(to->si_code, &from->si_code);
+
+ __get_user_ex(to->si_pid, &from->si_pid);
+ __get_user_ex(to->si_uid, &from->si_uid);
+ __get_user_ex(ptr32, &from->si_ptr);
to->si_ptr = compat_ptr(ptr32);

+ __get_user_ex_catch(&err);
+
return err;
}

@@ -142,31 +151,41 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
struct pt_regs *regs)
{
stack_t uss, uoss;
- int ret;
+ int ret, err = 0;
mm_segment_t seg;

+
if (uss_ptr) {
u32 ptr;

memset(&uss, 0, sizeof(stack_t));
- if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)) ||
- __get_user(ptr, &uss_ptr->ss_sp) ||
- __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
- __get_user(uss.ss_size, &uss_ptr->ss_size))
+ if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
return -EFAULT;
+ __get_user_ex_try();
+ __get_user_ex(ptr, &uss_ptr->ss_sp);
+ __get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
+ __get_user_ex(uss.ss_size, &uss_ptr->ss_size);
uss.ss_sp = compat_ptr(ptr);
+ __get_user_ex_catch(&err);
+ if (err)
+ return -EFAULT;
}
seg = get_fs();
set_fs(KERNEL_DS);
ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
set_fs(seg);
if (ret >= 0 && uoss_ptr) {
- if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)) ||
- __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
- __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
- __put_user(uoss.ss_size, &uoss_ptr->ss_size))
- ret = -EFAULT;
+ if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
+ return -EFAULT;
+ __put_user_ex_try();
+ __put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
+ __put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
+ __put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
+ __put_user_ex_catch(&ret);
+ if (err)
+ return -EFAULT;
}
+
return ret;
}

@@ -174,18 +193,18 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
* Do a signal return; undo the signal stack.
*/
#define COPY(x) { \
- err |= __get_user(regs->x, &sc->x); \
+ __get_user_ex(regs->x, &sc->x); \
}

#define COPY_SEG_CPL3(seg) { \
unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
+ __get_user_ex(tmp, &sc->seg); \
regs->seg = tmp | 3; \
}

#define RELOAD_SEG(seg) { \
unsigned int cur, pre; \
- err |= __get_user(pre, &sc->seg); \
+ __get_user_ex(pre, &sc->seg); \
savesegment(seg, cur); \
pre |= 3; \
if (pre != cur) \
@@ -203,6 +222,8 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;

+ __get_user_ex_try();
+
#if DEBUG_SIG
printk(KERN_DEBUG "SIG restore_sigcontext: "
"sc=%p err(%x) eip(%x) cs(%x) flg(%x)\n",
@@ -215,7 +236,7 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
* the handler, but does not clobber them at least in the
* normal case.
*/
- err |= __get_user(gs, &sc->gs);
+ __get_user_ex(gs, &sc->gs);
gs |= 3;
savesegment(gs, oldgs);
if (gs != oldgs)
@@ -232,16 +253,18 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
COPY_SEG_CPL3(cs);
COPY_SEG_CPL3(ss);

- err |= __get_user(tmpflags, &sc->flags);
+ __get_user_ex(tmpflags, &sc->flags);
regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
/* disable syscall checks */
regs->orig_ax = -1;

- err |= __get_user(tmp, &sc->fpstate);
+ __get_user_ex(tmp, &sc->fpstate);
buf = compat_ptr(tmp);
err |= restore_i387_xstate_ia32(buf);

- err |= __get_user(*pax, &sc->ax);
+ __get_user_ex(*pax, &sc->ax);
+
+ __get_user_ex_catch(&err);
return err;
}

@@ -319,36 +342,40 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
{
int tmp, err = 0;

+ __put_user_ex_try();
+
savesegment(gs, tmp);
- err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
+ __put_user_ex(tmp, (unsigned int __user *)&sc->gs);
savesegment(fs, tmp);
- err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
+ __put_user_ex(tmp, (unsigned int __user *)&sc->fs);
savesegment(ds, tmp);
- err |= __put_user(tmp, (unsigned int __user *)&sc->ds);
+ __put_user_ex(tmp, (unsigned int __user *)&sc->ds);
savesegment(es, tmp);
- err |= __put_user(tmp, (unsigned int __user *)&sc->es);
-
- err |= __put_user(regs->di, &sc->di);
- err |= __put_user(regs->si, &sc->si);
- err |= __put_user(regs->bp, &sc->bp);
- err |= __put_user(regs->sp, &sc->sp);
- err |= __put_user(regs->bx, &sc->bx);
- err |= __put_user(regs->dx, &sc->dx);
- err |= __put_user(regs->cx, &sc->cx);
- err |= __put_user(regs->ax, &sc->ax);
- err |= __put_user(current->thread.trap_no, &sc->trapno);
- err |= __put_user(current->thread.error_code, &sc->err);
- err |= __put_user(regs->ip, &sc->ip);
- err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs);
- err |= __put_user(regs->flags, &sc->flags);
- err |= __put_user(regs->sp, &sc->sp_at_signal);
- err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
-
- err |= __put_user(ptr_to_compat(fpstate), &sc->fpstate);
+ __put_user_ex(tmp, (unsigned int __user *)&sc->es);
+
+ __put_user_ex(regs->di, &sc->di);
+ __put_user_ex(regs->si, &sc->si);
+ __put_user_ex(regs->bp, &sc->bp);
+ __put_user_ex(regs->sp, &sc->sp);
+ __put_user_ex(regs->bx, &sc->bx);
+ __put_user_ex(regs->dx, &sc->dx);
+ __put_user_ex(regs->cx, &sc->cx);
+ __put_user_ex(regs->ax, &sc->ax);
+ __put_user_ex(current->thread.trap_no, &sc->trapno);
+ __put_user_ex(current->thread.error_code, &sc->err);
+ __put_user_ex(regs->ip, &sc->ip);
+ __put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
+ __put_user_ex(regs->flags, &sc->flags);
+ __put_user_ex(regs->sp, &sc->sp_at_signal);
+ __put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
+
+ __put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);

/* non-iBCS2 extensions.. */
- err |= __put_user(mask, &sc->oldmask);
- err |= __put_user(current->thread.cr2, &sc->cr2);
+ __put_user_ex(mask, &sc->oldmask);
+ __put_user_ex(current->thread.cr2, &sc->cr2);
+
+ __put_user_ex_catch(&err);

return err;
}
@@ -415,16 +442,19 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;

- if (__put_user(sig, &frame->sig))
- return -EFAULT;
+ __put_user_ex_try();

- if (ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]))
- return -EFAULT;
+ __put_user_ex(sig, &frame->sig);
+
+ err |= ia32_setup_sigcontext(&frame->sc, fpstate, regs, set->sig[0]);
+ if (err)
+ goto out;

if (_COMPAT_NSIG_WORDS > 1) {
- if (__copy_to_user(frame->extramask, &set->sig[1],
- sizeof(frame->extramask)))
- return -EFAULT;
+ err |= __copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask));
+ if (err)
+ goto out;
}

if (ka->sa.sa_flags & SA_RESTORER) {
@@ -437,15 +467,13 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
else
restorer = &frame->retcode;
}
- err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);
+ __put_user_ex(ptr_to_compat(restorer), &frame->pretcode);

/*
* These are actually not used anymore, but left because some
* gdb versions depend on them as a marker.
*/
- err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode);
- if (err)
- return -EFAULT;
+ __put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);

/* Set up registers for signal handler */
regs->sp = (unsigned long) frame;
@@ -467,7 +495,10 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
current->comm, current->pid, frame, regs->ip, frame->pretcode);
#endif

- return 0;
+out:
+ __put_user_ex_catch(&err);
+
+ return err;
}

int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
@@ -496,43 +527,43 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;

- err |= __put_user(sig, &frame->sig);
- err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);
- err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);
+ __put_user_ex_try();
+
+ __put_user_ex(sig, &frame->sig);
+ __put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
+ __put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
err |= copy_siginfo_to_user32(&frame->info, info);
if (err)
- return -EFAULT;
+ goto out;

/* Create the ucontext. */
if (cpu_has_xsave)
- err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
+ __put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
else
- err |= __put_user(0, &frame->uc.uc_flags);
- err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->sp),
+ __put_user_ex(0, &frame->uc.uc_flags);
+ __put_user_ex(0, &frame->uc.uc_link);
+ __put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ __put_user_ex(sas_ss_flags(regs->sp),
&frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ __put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
regs, set->sig[0]);
err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
if (err)
- return -EFAULT;
+ goto out;

if (ka->sa.sa_flags & SA_RESTORER)
restorer = ka->sa.sa_restorer;
else
restorer = VDSO32_SYMBOL(current->mm->context.vdso,
rt_sigreturn);
- err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);
+ __put_user_ex(ptr_to_compat(restorer), &frame->pretcode);

/*
* Not actually used anymore, but left because some gdb
* versions need it.
*/
- err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode);
- if (err)
- return -EFAULT;
+ __put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);

/* Set up registers for signal handler */
regs->sp = (unsigned long) frame;
@@ -554,5 +585,8 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
current->comm, current->pid, frame, regs->ip, frame->pretcode);
#endif

- return 0;
+out:
+ __put_user_ex_catch(&err);
+
+ return err;
}
--
1.6.0.4

2009-01-06 10:09:33

by Ingo Molnar

[permalink] [raw]
Subject: Re: [RFC -tip 0/4] x86: reduce fixup of uaccess


* Hiroshi Shimamoto <[email protected]> wrote:

> This is my second try to reduce fixup code size for exceptions of uaccess.
>
> This patch series reduces fixup code for exceptions of uaccess in signal.
>
> I gave up to make direct jump to end of function when an exception occurs.
> However, I thought fixup code could be reduced. The concept is that to add
> uaccess_err in thread_info and set it to -EFAULT on exception, finally check
> this value on the last of function.
>
> Is this good to reduce code size?
>
> The code size reductions are below;
> $ size *signal*.o.*
> text data bss dec hex filename
> 4741 0 0 4741 1285 ia32_signal.o.new
> 6006 0 0 6006 1776 ia32_signal.o.old
> 3577 0 0 3577 df9 signal.o.new
> 4540 0 0 4540 11bc signal.o.old
> 3855 0 0 3855 f0f signal32.o.new
> 4876 0 0 4876 130c signal32.o.old

looks very nice! Since kernel execution is i-cache-cold in the typical
case, this will probably transform into a performance improvement as well.

Ingo

2009-01-07 09:34:15

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [RFC -tip 0/4] x86: reduce fixup of uaccess

Hiroshi Shimamoto wrote:
> This is my second try to reduce fixup code size for exceptions of uaccess.
>
> This patch series reduces fixup code for exceptions of uaccess in signal.
>
> I gave up to make direct jump to end of function when an exception occurs.
> However, I thought fixup code could be reduced. The concept is that to add
> uaccess_err in thread_info and set it to -EFAULT on exception, finally check
> this value on the last of function.
>
> Is this good to reduce code size?
>

Hello Hiroshi,

The patches look technically really nice. I have a couple of stylistic
comments, though, which I'd like yours and others' comments on.

This introduces a new blocking construct, and it's not immediately
obvious in the source code. I think introducing a technically redundant
set of braces and dropping the parens from the try construct and the
redundant pointer might look better:

get_user_try {
/* do stuff */
} get_user_catch(err);

This makes it, in my opinion, much clearer that it is a new bracing
construct, and it also eliminates the need to form a pointer to "err"
(even though the compiler doesn't actually do so, it looks like it does
to the programmer.)

Also, I don't think we need double underscores for the wrapping
construct, since the get_user/__get_user (check/nocheck) etc.
distinction doesn't directly apply there.

What do you think?

-hpa

--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.

2009-01-08 01:44:24

by Hiroshi Shimamoto

[permalink] [raw]
Subject: Re: [RFC -tip 0/4] x86: reduce fixup of uaccess

H. Peter Anvin wrote:
> Hiroshi Shimamoto wrote:
>> This is my second try to reduce fixup code size for exceptions of uaccess.
>>
>> This patch series reduces fixup code for exceptions of uaccess in signal.
>>
>> I gave up to make direct jump to end of function when an exception occurs.
>> However, I thought fixup code could be reduced. The concept is that to add
>> uaccess_err in thread_info and set it to -EFAULT on exception, finally check
>> this value on the last of function.
>>
>> Is this good to reduce code size?
>>
>
> Hello Hiroshi,

Hello Peter,

>
> The patches look technically really nice. I have a couple of stylistic
> comments, though, which I'd like yours and others' comments on.

Thanks for comments.

>
> This introduces a new blocking construct, and it's not immediately
> obvious in the source code. I think introducing a technically redundant

Yeah, I think it's not friendly about readability now.

> set of braces and dropping the parens from the try construct and the
> redundant pointer might look better:
>
> get_user_try {
> /* do stuff */
> } get_user_catch(err);

OK, I'll update like that.

>
> This makes it, in my opinion, much clearer that it is a new bracing
> construct, and it also eliminates the need to form a pointer to "err"

I'm not sure which is better plain "err" or pointer to "err".

> (even though the compiler doesn't actually do so, it looks like it does
> to the programmer.)
>
> Also, I don't think we need double underscores for the wrapping
> construct, since the get_user/__get_user (check/nocheck) etc.
> distinction doesn't directly apply there.

OK. Will drop underscores.

I'll repost update patches.

Thanks,
Hiroshi

2009-01-23 23:48:21

by Hiroshi Shimamoto

[permalink] [raw]
Subject: [RFC v2 -tip 0/3] x86: reduce fixup of uaccess

This patch series redues fixup code for exceptions of uaccess in signal.

There is a lot of fixup code which is generated by using __{get|put}_user.
I think that code can be reduced. The concept is that to add uaccess_err in
thread_info and set it to -EFAULT on exception, finally check this value on
the last of function.

The code size reductions are below;
$ size *signal*.o.*
text data bss dec hex filename
4596 0 0 4596 11f4 ia32_signal.o.new
6006 0 0 6006 1776 ia32_signal.o.old
3583 0 0 3583 dff signal.o.new
4540 0 0 4540 11bc signal.o.old
3863 0 0 3863 f17 signal32.o.new
4876 0 0 4876 130c signal32.o.old
[ signal32.o means signal.o on 32-bit. ]

ChangeLog v1 -> v2
- Change framework syntax. Previous version doesn't look easy to read.
Remove parens from try and add redundant braces as Peter suggested.
get_user_try {
get_user_ex(...);
:
} get_user_catch(err);
- Remove double underscores.

2009-01-23 23:49:50

by Hiroshi Shimamoto

[permalink] [raw]
Subject: [RFC v2 -tip 1/3] x86: uaccess: introduce try and catch framework

From: Hiroshi Shimamoto <[email protected]>

Impact: introduce new uaccess exception handling framework

Introduce {get|put}_user_try and {get|put}_user_catch as new uaccess exception
handling framework.
{get|put}_user_try begins exception block and {get|put}_user_catch(err) ends
the block and gets err if an exception occured in {get|put}_user_ex() in the
block. The exception is stored thread_info->uaccess_err.

The example usage of this framework is below;
int func()
{
int err = 0;

get_user_try {
get_user_ex(...);
get_user_ex(...);
:
} get_user_catch(err);

return err;
}

Note: get_user_ex() is not clear the value when an exception occurs, it's
different from the behavior of __get_user(), but I think it doesn't matter.

Signed-off-by: Hiroshi Shimamoto <[email protected]>
---
arch/x86/include/asm/thread_info.h | 1 +
arch/x86/include/asm/uaccess.h | 103 ++++++++++++++++++++++++++++++++++++
arch/x86/mm/extable.c | 6 ++
3 files changed, 110 insertions(+), 0 deletions(-)

diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index f384889..ca7310e 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -40,6 +40,7 @@ struct thread_info {
*/
__u8 supervisor_stack[0];
#endif
+ int uaccess_err;
};

#define INIT_THREAD_INFO(tsk) \
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 69d2757..0ec6de4 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -199,12 +199,22 @@ extern int __get_user_bad(void);
: "=r" (err) \
: "A" (x), "r" (addr), "i" (-EFAULT), "0" (err))

+#define __put_user_asm_ex_u64(x, addr) \
+ asm volatile("1: movl %%eax,0(%1)\n" \
+ "2: movl %%edx,4(%1)\n" \
+ "3:\n" \
+ _ASM_EXTABLE(1b, 2b - 1b) \
+ _ASM_EXTABLE(2b, 3b - 2b) \
+ : : "A" (x), "r" (addr))
+
#define __put_user_x8(x, ptr, __ret_pu) \
asm volatile("call __put_user_8" : "=a" (__ret_pu) \
: "A" ((typeof(*(ptr)))(x)), "c" (ptr) : "ebx")
#else
#define __put_user_asm_u64(x, ptr, retval) \
__put_user_asm(x, ptr, retval, "q", "", "Zr", -EFAULT)
+#define __put_user_asm_ex_u64(x, addr) \
+ __put_user_asm_ex(x, addr, "q", "", "Zr")
#define __put_user_x8(x, ptr, __ret_pu) __put_user_x(8, x, ptr, __ret_pu)
#endif

@@ -286,6 +296,27 @@ do { \
} \
} while (0)

+#define __put_user_size_ex(x, ptr, size) \
+do { \
+ __chk_user_ptr(ptr); \
+ switch (size) { \
+ case 1: \
+ __put_user_asm_ex(x, ptr, "b", "b", "iq"); \
+ break; \
+ case 2: \
+ __put_user_asm_ex(x, ptr, "w", "w", "ir"); \
+ break; \
+ case 4: \
+ __put_user_asm_ex(x, ptr, "l", "k", "ir"); \
+ break; \
+ case 8: \
+ __put_user_asm_ex_u64((__typeof__(*ptr))(x), ptr); \
+ break; \
+ default: \
+ __put_user_bad(); \
+ } \
+} while (0)
+
#else

#define __put_user_size(x, ptr, size, retval, errret) \
@@ -311,9 +342,12 @@ do { \

#ifdef CONFIG_X86_32
#define __get_user_asm_u64(x, ptr, retval, errret) (x) = __get_user_bad()
+#define __get_user_asm_ex_u64(x, ptr) (x) = __get_user_bad()
#else
#define __get_user_asm_u64(x, ptr, retval, errret) \
__get_user_asm(x, ptr, retval, "q", "", "=r", errret)
+#define __get_user_asm_ex_u64(x, ptr) \
+ __get_user_asm_ex(x, ptr, "q", "", "=r")
#endif

#define __get_user_size(x, ptr, size, retval, errret) \
@@ -350,6 +384,33 @@ do { \
: "=r" (err), ltype(x) \
: "m" (__m(addr)), "i" (errret), "0" (err))

+#define __get_user_size_ex(x, ptr, size) \
+do { \
+ __chk_user_ptr(ptr); \
+ switch (size) { \
+ case 1: \
+ __get_user_asm_ex(x, ptr, "b", "b", "=q"); \
+ break; \
+ case 2: \
+ __get_user_asm_ex(x, ptr, "w", "w", "=r"); \
+ break; \
+ case 4: \
+ __get_user_asm_ex(x, ptr, "l", "k", "=r"); \
+ break; \
+ case 8: \
+ __get_user_asm_ex_u64(x, ptr); \
+ break; \
+ default: \
+ (x) = __get_user_bad(); \
+ } \
+} while (0)
+
+#define __get_user_asm_ex(x, addr, itype, rtype, ltype) \
+ asm volatile("1: mov"itype" %1,%"rtype"0\n" \
+ "2:\n" \
+ _ASM_EXTABLE(1b, 2b - 1b) \
+ : ltype(x) : "m" (__m(addr)))
+
#define __put_user_nocheck(x, ptr, size) \
({ \
int __pu_err; \
@@ -385,6 +446,26 @@ struct __large_struct { unsigned long buf[100]; };
_ASM_EXTABLE(1b, 3b) \
: "=r"(err) \
: ltype(x), "m" (__m(addr)), "i" (errret), "0" (err))
+
+#define __put_user_asm_ex(x, addr, itype, rtype, ltype) \
+ asm volatile("1: mov"itype" %"rtype"0,%1\n" \
+ "2:\n" \
+ _ASM_EXTABLE(1b, 2b - 1b) \
+ : : ltype(x), "m" (__m(addr)))
+
+/*
+ * uaccess_try and catch
+ */
+#define uaccess_try do { \
+ int prev_err = current_thread_info()->uaccess_err; \
+ current_thread_info()->uaccess_err = 0; \
+ barrier();
+
+#define uaccess_catch(err) \
+ (err) |= current_thread_info()->uaccess_err; \
+ current_thread_info()->uaccess_err = prev_err; \
+} while (0)
+
/**
* __get_user: - Get a simple variable from user space, with less checking.
* @x: Variable to store result.
@@ -408,6 +489,7 @@ struct __large_struct { unsigned long buf[100]; };

#define __get_user(x, ptr) \
__get_user_nocheck((x), (ptr), sizeof(*(ptr)))
+
/**
* __put_user: - Write a simple value into user space, with less checking.
* @x: Value to copy to user space.
@@ -435,6 +517,27 @@ struct __large_struct { unsigned long buf[100]; };
#define __put_user_unaligned __put_user

/*
+ * {get|put}_user_try and catch
+ *
+ * get_user_try {
+ * get_user_ex(...);
+ * } get_user_catch(err)
+ */
+#define get_user_try uaccess_try
+#define get_user_catch(err) uaccess_catch(err)
+#define put_user_try uaccess_try
+#define put_user_catch(err) uaccess_catch(err)
+
+#define get_user_ex(x, ptr) do { \
+ unsigned long __gue_val; \
+ __get_user_size_ex((__gue_val), (ptr), (sizeof(*(ptr)))); \
+ (x) = (__force __typeof__(*(ptr)))__gue_val; \
+} while (0)
+
+#define put_user_ex(x, ptr) \
+ __put_user_size_ex((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)))
+
+/*
* movsl can be slow when source and dest are not both 8-byte aligned
*/
#ifdef CONFIG_X86_INTEL_USERCOPY
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 7e8db53..61b41ca 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -23,6 +23,12 @@ int fixup_exception(struct pt_regs *regs)

fixup = search_exception_tables(regs->ip);
if (fixup) {
+ /* If fixup is less than 16, it means uaccess error */
+ if (fixup->fixup < 16) {
+ current_thread_info()->uaccess_err = -EFAULT;
+ regs->ip += fixup->fixup;
+ return 1;
+ }
regs->ip = fixup->fixup;
return 1;
}
--
1.6.0.4

2009-01-23 23:50:28

by Hiroshi Shimamoto

[permalink] [raw]
Subject: [RFC v2 -tip 2/3] x86: signal: use {get|put}_user_try and catch

From: Hiroshi Shimamoto <[email protected]>

Impact: use new framework

Use {get|put}_user_try, catch, and _ex in arch/x86/kernel/signal.c.

Note: this patch contains "WARNING: line over 80 characters", because when
introducing new block I insert an indent to avoid mistakes by edit.

Signed-off-by: Hiroshi Shimamoto <[email protected]>
---
arch/x86/kernel/signal.c | 297 ++++++++++++++++++++++++----------------------
1 files changed, 157 insertions(+), 140 deletions(-)

diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index 0bc73d6..40e089b 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -51,24 +51,24 @@
#endif

#define COPY(x) { \
- err |= __get_user(regs->x, &sc->x); \
+ get_user_ex(regs->x, &sc->x); \
}

#define COPY_SEG(seg) { \
unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
+ get_user_ex(tmp, &sc->seg); \
regs->seg = tmp; \
}

#define COPY_SEG_CPL3(seg) { \
unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
+ get_user_ex(tmp, &sc->seg); \
regs->seg = tmp | 3; \
}

#define GET_SEG(seg) { \
unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
+ get_user_ex(tmp, &sc->seg); \
loadsegment(seg, tmp); \
}

@@ -83,45 +83,49 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
/* Always make any pending restarted system calls return -EINTR */
current_thread_info()->restart_block.fn = do_no_restart_syscall;

+ get_user_try {
+
#ifdef CONFIG_X86_32
- GET_SEG(gs);
- COPY_SEG(fs);
- COPY_SEG(es);
- COPY_SEG(ds);
+ GET_SEG(gs);
+ COPY_SEG(fs);
+ COPY_SEG(es);
+ COPY_SEG(ds);
#endif /* CONFIG_X86_32 */

- COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
- COPY(dx); COPY(cx); COPY(ip);
+ COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
+ COPY(dx); COPY(cx); COPY(ip);

#ifdef CONFIG_X86_64
- COPY(r8);
- COPY(r9);
- COPY(r10);
- COPY(r11);
- COPY(r12);
- COPY(r13);
- COPY(r14);
- COPY(r15);
+ COPY(r8);
+ COPY(r9);
+ COPY(r10);
+ COPY(r11);
+ COPY(r12);
+ COPY(r13);
+ COPY(r14);
+ COPY(r15);
#endif /* CONFIG_X86_64 */

#ifdef CONFIG_X86_32
- COPY_SEG_CPL3(cs);
- COPY_SEG_CPL3(ss);
+ COPY_SEG_CPL3(cs);
+ COPY_SEG_CPL3(ss);
#else /* !CONFIG_X86_32 */
- /* Kernel saves and restores only the CS segment register on signals,
- * which is the bare minimum needed to allow mixed 32/64-bit code.
- * App's signal handler can save/restore other segments if needed. */
- COPY_SEG_CPL3(cs);
+ /* Kernel saves and restores only the CS segment register on signals,
+ * which is the bare minimum needed to allow mixed 32/64-bit code.
+ * App's signal handler can save/restore other segments if needed. */
+ COPY_SEG_CPL3(cs);
#endif /* CONFIG_X86_32 */

- err |= __get_user(tmpflags, &sc->flags);
- regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
- regs->orig_ax = -1; /* disable syscall checks */
+ get_user_ex(tmpflags, &sc->flags);
+ regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+ regs->orig_ax = -1; /* disable syscall checks */
+
+ get_user_ex(buf, &sc->fpstate);
+ err |= restore_i387_xstate(buf);

- err |= __get_user(buf, &sc->fpstate);
- err |= restore_i387_xstate(buf);
+ get_user_ex(*pax, &sc->ax);
+ } get_user_catch(err);

- err |= __get_user(*pax, &sc->ax);
return err;
}

@@ -131,57 +135,60 @@ setup_sigcontext(struct sigcontext __user *sc, void __user *fpstate,
{
int err = 0;

+ put_user_try {
+
#ifdef CONFIG_X86_32
- {
- unsigned int tmp;
+ {
+ unsigned int tmp;

- savesegment(gs, tmp);
- err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
- }
- err |= __put_user(regs->fs, (unsigned int __user *)&sc->fs);
- err |= __put_user(regs->es, (unsigned int __user *)&sc->es);
- err |= __put_user(regs->ds, (unsigned int __user *)&sc->ds);
+ savesegment(gs, tmp);
+ put_user_ex(tmp, (unsigned int __user *)&sc->gs);
+ }
+ put_user_ex(regs->fs, (unsigned int __user *)&sc->fs);
+ put_user_ex(regs->es, (unsigned int __user *)&sc->es);
+ put_user_ex(regs->ds, (unsigned int __user *)&sc->ds);
#endif /* CONFIG_X86_32 */

- err |= __put_user(regs->di, &sc->di);
- err |= __put_user(regs->si, &sc->si);
- err |= __put_user(regs->bp, &sc->bp);
- err |= __put_user(regs->sp, &sc->sp);
- err |= __put_user(regs->bx, &sc->bx);
- err |= __put_user(regs->dx, &sc->dx);
- err |= __put_user(regs->cx, &sc->cx);
- err |= __put_user(regs->ax, &sc->ax);
+ put_user_ex(regs->di, &sc->di);
+ put_user_ex(regs->si, &sc->si);
+ put_user_ex(regs->bp, &sc->bp);
+ put_user_ex(regs->sp, &sc->sp);
+ put_user_ex(regs->bx, &sc->bx);
+ put_user_ex(regs->dx, &sc->dx);
+ put_user_ex(regs->cx, &sc->cx);
+ put_user_ex(regs->ax, &sc->ax);
#ifdef CONFIG_X86_64
- err |= __put_user(regs->r8, &sc->r8);
- err |= __put_user(regs->r9, &sc->r9);
- err |= __put_user(regs->r10, &sc->r10);
- err |= __put_user(regs->r11, &sc->r11);
- err |= __put_user(regs->r12, &sc->r12);
- err |= __put_user(regs->r13, &sc->r13);
- err |= __put_user(regs->r14, &sc->r14);
- err |= __put_user(regs->r15, &sc->r15);
+ put_user_ex(regs->r8, &sc->r8);
+ put_user_ex(regs->r9, &sc->r9);
+ put_user_ex(regs->r10, &sc->r10);
+ put_user_ex(regs->r11, &sc->r11);
+ put_user_ex(regs->r12, &sc->r12);
+ put_user_ex(regs->r13, &sc->r13);
+ put_user_ex(regs->r14, &sc->r14);
+ put_user_ex(regs->r15, &sc->r15);
#endif /* CONFIG_X86_64 */

- err |= __put_user(current->thread.trap_no, &sc->trapno);
- err |= __put_user(current->thread.error_code, &sc->err);
- err |= __put_user(regs->ip, &sc->ip);
+ put_user_ex(current->thread.trap_no, &sc->trapno);
+ put_user_ex(current->thread.error_code, &sc->err);
+ put_user_ex(regs->ip, &sc->ip);
#ifdef CONFIG_X86_32
- err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs);
- err |= __put_user(regs->flags, &sc->flags);
- err |= __put_user(regs->sp, &sc->sp_at_signal);
- err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
+ put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
+ put_user_ex(regs->flags, &sc->flags);
+ put_user_ex(regs->sp, &sc->sp_at_signal);
+ put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
#else /* !CONFIG_X86_32 */
- err |= __put_user(regs->flags, &sc->flags);
- err |= __put_user(regs->cs, &sc->cs);
- err |= __put_user(0, &sc->gs);
- err |= __put_user(0, &sc->fs);
+ put_user_ex(regs->flags, &sc->flags);
+ put_user_ex(regs->cs, &sc->cs);
+ put_user_ex(0, &sc->gs);
+ put_user_ex(0, &sc->fs);
#endif /* CONFIG_X86_32 */

- err |= __put_user(fpstate, &sc->fpstate);
+ put_user_ex(fpstate, &sc->fpstate);

- /* non-iBCS2 extensions.. */
- err |= __put_user(mask, &sc->oldmask);
- err |= __put_user(current->thread.cr2, &sc->cr2);
+ /* non-iBCS2 extensions.. */
+ put_user_ex(mask, &sc->oldmask);
+ put_user_ex(current->thread.cr2, &sc->cr2);
+ } put_user_catch(err);

return err;
}
@@ -336,43 +343,41 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;

- err |= __put_user(sig, &frame->sig);
- err |= __put_user(&frame->info, &frame->pinfo);
- err |= __put_user(&frame->uc, &frame->puc);
- err |= copy_siginfo_to_user(&frame->info, info);
- if (err)
- return -EFAULT;
-
- /* Create the ucontext. */
- if (cpu_has_xsave)
- err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
- else
- err |= __put_user(0, &frame->uc.uc_flags);
- err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->sp),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
- err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
- regs, set->sig[0]);
- err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
- if (err)
- return -EFAULT;
+ put_user_try {
+ put_user_ex(sig, &frame->sig);
+ put_user_ex(&frame->info, &frame->pinfo);
+ put_user_ex(&frame->uc, &frame->puc);
+ err |= copy_siginfo_to_user(&frame->info, info);

- /* Set up to return from userspace. */
- restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
- if (ka->sa.sa_flags & SA_RESTORER)
- restorer = ka->sa.sa_restorer;
- err |= __put_user(restorer, &frame->pretcode);
+ /* Create the ucontext. */
+ if (cpu_has_xsave)
+ put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
+ else
+ put_user_ex(0, &frame->uc.uc_flags);
+ put_user_ex(0, &frame->uc.uc_link);
+ put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ put_user_ex(sas_ss_flags(regs->sp),
+ &frame->uc.uc_stack.ss_flags);
+ put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+ regs, set->sig[0]);
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+ /* Set up to return from userspace. */
+ restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn);
+ if (ka->sa.sa_flags & SA_RESTORER)
+ restorer = ka->sa.sa_restorer;
+ put_user_ex(restorer, &frame->pretcode);

- /*
- * This is movl $__NR_rt_sigreturn, %ax ; int $0x80
- *
- * WE DO NOT USE IT ANY MORE! It's only left here for historical
- * reasons and because gdb uses it as a signature to notice
- * signal handler stack frames.
- */
- err |= __put_user(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
+ /*
+ * This is movl $__NR_rt_sigreturn, %ax ; int $0x80
+ *
+ * WE DO NOT USE IT ANY MORE! It's only left here for historical
+ * reasons and because gdb uses it as a signature to notice
+ * signal handler stack frames.
+ */
+ put_user_ex(*((u64 *)&rt_retcode), (u64 *)frame->retcode);
+ } put_user_catch(err);

if (err)
return -EFAULT;
@@ -436,28 +441,30 @@ static int __setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
return -EFAULT;
}

- /* Create the ucontext. */
- if (cpu_has_xsave)
- err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
- else
- err |= __put_user(0, &frame->uc.uc_flags);
- err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->sp),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
- err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
- err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
-
- /* Set up to return from userspace. If provided, use a stub
- already in userspace. */
- /* x86-64 should always use SA_RESTORER. */
- if (ka->sa.sa_flags & SA_RESTORER) {
- err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
- } else {
- /* could use a vstub here */
- return -EFAULT;
- }
+ put_user_try {
+ /* Create the ucontext. */
+ if (cpu_has_xsave)
+ put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
+ else
+ put_user_ex(0, &frame->uc.uc_flags);
+ put_user_ex(0, &frame->uc.uc_link);
+ put_user_ex(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ put_user_ex(sas_ss_flags(regs->sp),
+ &frame->uc.uc_stack.ss_flags);
+ put_user_ex(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= setup_sigcontext(&frame->uc.uc_mcontext, fp, regs, set->sig[0]);
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+ /* Set up to return from userspace. If provided, use a stub
+ already in userspace. */
+ /* x86-64 should always use SA_RESTORER. */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ put_user_ex(ka->sa.sa_restorer, &frame->pretcode);
+ } else {
+ /* could use a vstub here */
+ err |= -EFAULT;
+ }
+ } put_user_catch(err);

if (err)
return -EFAULT;
@@ -509,31 +516,41 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
struct old_sigaction __user *oact)
{
struct k_sigaction new_ka, old_ka;
- int ret;
+ int ret = 0;

if (act) {
old_sigset_t mask;

- if (!access_ok(VERIFY_READ, act, sizeof(*act)) ||
- __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
- __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
+ if (!access_ok(VERIFY_READ, act, sizeof(*act)))
return -EFAULT;

- __get_user(new_ka.sa.sa_flags, &act->sa_flags);
- __get_user(mask, &act->sa_mask);
+ get_user_try {
+ get_user_ex(new_ka.sa.sa_handler, &act->sa_handler);
+ get_user_ex(new_ka.sa.sa_flags, &act->sa_flags);
+ get_user_ex(mask, &act->sa_mask);
+ get_user_ex(new_ka.sa.sa_restorer, &act->sa_restorer);
+ } get_user_catch(ret);
+
+ if (ret)
+ return -EFAULT;
siginitset(&new_ka.sa.sa_mask, mask);
}

ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);

if (!ret && oact) {
- if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) ||
- __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
- __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
+ if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
return -EFAULT;

- __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
- __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ put_user_try {
+ put_user_ex(old_ka.sa.sa_handler, &oact->sa_handler);
+ put_user_ex(old_ka.sa.sa_flags, &oact->sa_flags);
+ put_user_ex(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
+ put_user_ex(old_ka.sa.sa_restorer, &oact->sa_restorer);
+ } put_user_catch(ret);
+
+ if (ret)
+ return -EFAULT;
}

return ret;
--
1.6.0.4

2009-01-23 23:50:52

by Hiroshi Shimamoto

[permalink] [raw]
Subject: [RFC v2 -tip 3/3] x86: ia32_signal: use {get|put}_user_try and catch

From: Hiroshi Shimamoto <[email protected]>

Impact: use new framework

Use {get|put}_user_try, catch, and _ex in arch/x86/ia32/ia32_signal.c.

Note: this patch contains "WARNING: line over 80 characters", because when
introducing new block I insert an indent to avoid mistakes by edit.

Signed-off-by: Hiroshi Shimamoto <[email protected]>
---
arch/x86/ia32/ia32_signal.c | 365 +++++++++++++++++++++++--------------------
1 files changed, 195 insertions(+), 170 deletions(-)

diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
index 9dabd00..dd77ac0 100644
--- a/arch/x86/ia32/ia32_signal.c
+++ b/arch/x86/ia32/ia32_signal.c
@@ -46,78 +46,83 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where);

int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
{
- int err;
+ int err = 0;

if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
return -EFAULT;

- /* If you change siginfo_t structure, please make sure that
- this code is fixed accordingly.
- It should never copy any pad contained in the structure
- to avoid security leaks, but must copy the generic
- 3 ints plus the relevant union member. */
- err = __put_user(from->si_signo, &to->si_signo);
- err |= __put_user(from->si_errno, &to->si_errno);
- err |= __put_user((short)from->si_code, &to->si_code);
-
- if (from->si_code < 0) {
- err |= __put_user(from->si_pid, &to->si_pid);
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(ptr_to_compat(from->si_ptr), &to->si_ptr);
- } else {
- /*
- * First 32bits of unions are always present:
- * si_pid === si_band === si_tid === si_addr(LS half)
- */
- err |= __put_user(from->_sifields._pad[0],
- &to->_sifields._pad[0]);
- switch (from->si_code >> 16) {
- case __SI_FAULT >> 16:
- break;
- case __SI_CHLD >> 16:
- err |= __put_user(from->si_utime, &to->si_utime);
- err |= __put_user(from->si_stime, &to->si_stime);
- err |= __put_user(from->si_status, &to->si_status);
- /* FALL THROUGH */
- default:
- case __SI_KILL >> 16:
- err |= __put_user(from->si_uid, &to->si_uid);
- break;
- case __SI_POLL >> 16:
- err |= __put_user(from->si_fd, &to->si_fd);
- break;
- case __SI_TIMER >> 16:
- err |= __put_user(from->si_overrun, &to->si_overrun);
- err |= __put_user(ptr_to_compat(from->si_ptr),
- &to->si_ptr);
- break;
- /* This is not generated by the kernel as of now. */
- case __SI_RT >> 16:
- case __SI_MESGQ >> 16:
- err |= __put_user(from->si_uid, &to->si_uid);
- err |= __put_user(from->si_int, &to->si_int);
- break;
+ put_user_try {
+ /* If you change siginfo_t structure, please make sure that
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member. */
+ put_user_ex(from->si_signo, &to->si_signo);
+ put_user_ex(from->si_errno, &to->si_errno);
+ put_user_ex((short)from->si_code, &to->si_code);
+
+ if (from->si_code < 0) {
+ put_user_ex(from->si_pid, &to->si_pid);
+ put_user_ex(from->si_uid, &to->si_uid);
+ put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
+ } else {
+ /*
+ * First 32bits of unions are always present:
+ * si_pid === si_band === si_tid === si_addr(LS half)
+ */
+ put_user_ex(from->_sifields._pad[0],
+ &to->_sifields._pad[0]);
+ switch (from->si_code >> 16) {
+ case __SI_FAULT >> 16:
+ break;
+ case __SI_CHLD >> 16:
+ put_user_ex(from->si_utime, &to->si_utime);
+ put_user_ex(from->si_stime, &to->si_stime);
+ put_user_ex(from->si_status, &to->si_status);
+ /* FALL THROUGH */
+ default:
+ case __SI_KILL >> 16:
+ put_user_ex(from->si_uid, &to->si_uid);
+ break;
+ case __SI_POLL >> 16:
+ put_user_ex(from->si_fd, &to->si_fd);
+ break;
+ case __SI_TIMER >> 16:
+ put_user_ex(from->si_overrun, &to->si_overrun);
+ put_user_ex(ptr_to_compat(from->si_ptr),
+ &to->si_ptr);
+ break;
+ /* This is not generated by the kernel as of now. */
+ case __SI_RT >> 16:
+ case __SI_MESGQ >> 16:
+ put_user_ex(from->si_uid, &to->si_uid);
+ put_user_ex(from->si_int, &to->si_int);
+ break;
+ }
}
- }
+ } put_user_catch(err);
+
return err;
}

int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
{
- int err;
+ int err = 0;
u32 ptr32;

if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
return -EFAULT;

- err = __get_user(to->si_signo, &from->si_signo);
- err |= __get_user(to->si_errno, &from->si_errno);
- err |= __get_user(to->si_code, &from->si_code);
+ get_user_try {
+ get_user_ex(to->si_signo, &from->si_signo);
+ get_user_ex(to->si_errno, &from->si_errno);
+ get_user_ex(to->si_code, &from->si_code);

- err |= __get_user(to->si_pid, &from->si_pid);
- err |= __get_user(to->si_uid, &from->si_uid);
- err |= __get_user(ptr32, &from->si_ptr);
- to->si_ptr = compat_ptr(ptr32);
+ get_user_ex(to->si_pid, &from->si_pid);
+ get_user_ex(to->si_uid, &from->si_uid);
+ get_user_ex(ptr32, &from->si_ptr);
+ to->si_ptr = compat_ptr(ptr32);
+ } get_user_catch(err);

return err;
}
@@ -142,17 +147,23 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
struct pt_regs *regs)
{
stack_t uss, uoss;
- int ret;
+ int ret, err = 0;
mm_segment_t seg;

if (uss_ptr) {
u32 ptr;

memset(&uss, 0, sizeof(stack_t));
- if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)) ||
- __get_user(ptr, &uss_ptr->ss_sp) ||
- __get_user(uss.ss_flags, &uss_ptr->ss_flags) ||
- __get_user(uss.ss_size, &uss_ptr->ss_size))
+ if (!access_ok(VERIFY_READ, uss_ptr, sizeof(stack_ia32_t)))
+ return -EFAULT;
+
+ get_user_try {
+ get_user_ex(ptr, &uss_ptr->ss_sp);
+ get_user_ex(uss.ss_flags, &uss_ptr->ss_flags);
+ get_user_ex(uss.ss_size, &uss_ptr->ss_size);
+ } get_user_catch(err);
+
+ if (err)
return -EFAULT;
uss.ss_sp = compat_ptr(ptr);
}
@@ -161,10 +172,16 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
ret = do_sigaltstack(uss_ptr ? &uss : NULL, &uoss, regs->sp);
set_fs(seg);
if (ret >= 0 && uoss_ptr) {
- if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)) ||
- __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) ||
- __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) ||
- __put_user(uoss.ss_size, &uoss_ptr->ss_size))
+ if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(stack_ia32_t)))
+ return -EFAULT;
+
+ put_user_try {
+ put_user_ex(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp);
+ put_user_ex(uoss.ss_flags, &uoss_ptr->ss_flags);
+ put_user_ex(uoss.ss_size, &uoss_ptr->ss_size);
+ } put_user_catch(err);
+
+ if (err)
ret = -EFAULT;
}
return ret;
@@ -174,18 +191,18 @@ asmlinkage long sys32_sigaltstack(const stack_ia32_t __user *uss_ptr,
* Do a signal return; undo the signal stack.
*/
#define COPY(x) { \
- err |= __get_user(regs->x, &sc->x); \
+ get_user_ex(regs->x, &sc->x); \
}

#define COPY_SEG_CPL3(seg) { \
unsigned short tmp; \
- err |= __get_user(tmp, &sc->seg); \
+ get_user_ex(tmp, &sc->seg); \
regs->seg = tmp | 3; \
}

#define RELOAD_SEG(seg) { \
unsigned int cur, pre; \
- err |= __get_user(pre, &sc->seg); \
+ get_user_ex(pre, &sc->seg); \
savesegment(seg, cur); \
pre |= 3; \
if (pre != cur) \
@@ -209,39 +226,42 @@ static int ia32_restore_sigcontext(struct pt_regs *regs,
sc, sc->err, sc->ip, sc->cs, sc->flags);
#endif

- /*
- * Reload fs and gs if they have changed in the signal
- * handler. This does not handle long fs/gs base changes in
- * the handler, but does not clobber them at least in the
- * normal case.
- */
- err |= __get_user(gs, &sc->gs);
- gs |= 3;
- savesegment(gs, oldgs);
- if (gs != oldgs)
- load_gs_index(gs);
-
- RELOAD_SEG(fs);
- RELOAD_SEG(ds);
- RELOAD_SEG(es);
-
- COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
- COPY(dx); COPY(cx); COPY(ip);
- /* Don't touch extended registers */
-
- COPY_SEG_CPL3(cs);
- COPY_SEG_CPL3(ss);
-
- err |= __get_user(tmpflags, &sc->flags);
- regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
- /* disable syscall checks */
- regs->orig_ax = -1;
-
- err |= __get_user(tmp, &sc->fpstate);
- buf = compat_ptr(tmp);
- err |= restore_i387_xstate_ia32(buf);
-
- err |= __get_user(*pax, &sc->ax);
+ get_user_try {
+ /*
+ * Reload fs and gs if they have changed in the signal
+ * handler. This does not handle long fs/gs base changes in
+ * the handler, but does not clobber them at least in the
+ * normal case.
+ */
+ get_user_ex(gs, &sc->gs);
+ gs |= 3;
+ savesegment(gs, oldgs);
+ if (gs != oldgs)
+ load_gs_index(gs);
+
+ RELOAD_SEG(fs);
+ RELOAD_SEG(ds);
+ RELOAD_SEG(es);
+
+ COPY(di); COPY(si); COPY(bp); COPY(sp); COPY(bx);
+ COPY(dx); COPY(cx); COPY(ip);
+ /* Don't touch extended registers */
+
+ COPY_SEG_CPL3(cs);
+ COPY_SEG_CPL3(ss);
+
+ get_user_ex(tmpflags, &sc->flags);
+ regs->flags = (regs->flags & ~FIX_EFLAGS) | (tmpflags & FIX_EFLAGS);
+ /* disable syscall checks */
+ regs->orig_ax = -1;
+
+ get_user_ex(tmp, &sc->fpstate);
+ buf = compat_ptr(tmp);
+ err |= restore_i387_xstate_ia32(buf);
+
+ get_user_ex(*pax, &sc->ax);
+ } get_user_catch(err);
+
return err;
}

@@ -319,36 +339,38 @@ static int ia32_setup_sigcontext(struct sigcontext_ia32 __user *sc,
{
int tmp, err = 0;

- savesegment(gs, tmp);
- err |= __put_user(tmp, (unsigned int __user *)&sc->gs);
- savesegment(fs, tmp);
- err |= __put_user(tmp, (unsigned int __user *)&sc->fs);
- savesegment(ds, tmp);
- err |= __put_user(tmp, (unsigned int __user *)&sc->ds);
- savesegment(es, tmp);
- err |= __put_user(tmp, (unsigned int __user *)&sc->es);
-
- err |= __put_user(regs->di, &sc->di);
- err |= __put_user(regs->si, &sc->si);
- err |= __put_user(regs->bp, &sc->bp);
- err |= __put_user(regs->sp, &sc->sp);
- err |= __put_user(regs->bx, &sc->bx);
- err |= __put_user(regs->dx, &sc->dx);
- err |= __put_user(regs->cx, &sc->cx);
- err |= __put_user(regs->ax, &sc->ax);
- err |= __put_user(current->thread.trap_no, &sc->trapno);
- err |= __put_user(current->thread.error_code, &sc->err);
- err |= __put_user(regs->ip, &sc->ip);
- err |= __put_user(regs->cs, (unsigned int __user *)&sc->cs);
- err |= __put_user(regs->flags, &sc->flags);
- err |= __put_user(regs->sp, &sc->sp_at_signal);
- err |= __put_user(regs->ss, (unsigned int __user *)&sc->ss);
-
- err |= __put_user(ptr_to_compat(fpstate), &sc->fpstate);
-
- /* non-iBCS2 extensions.. */
- err |= __put_user(mask, &sc->oldmask);
- err |= __put_user(current->thread.cr2, &sc->cr2);
+ put_user_try {
+ savesegment(gs, tmp);
+ put_user_ex(tmp, (unsigned int __user *)&sc->gs);
+ savesegment(fs, tmp);
+ put_user_ex(tmp, (unsigned int __user *)&sc->fs);
+ savesegment(ds, tmp);
+ put_user_ex(tmp, (unsigned int __user *)&sc->ds);
+ savesegment(es, tmp);
+ put_user_ex(tmp, (unsigned int __user *)&sc->es);
+
+ put_user_ex(regs->di, &sc->di);
+ put_user_ex(regs->si, &sc->si);
+ put_user_ex(regs->bp, &sc->bp);
+ put_user_ex(regs->sp, &sc->sp);
+ put_user_ex(regs->bx, &sc->bx);
+ put_user_ex(regs->dx, &sc->dx);
+ put_user_ex(regs->cx, &sc->cx);
+ put_user_ex(regs->ax, &sc->ax);
+ put_user_ex(current->thread.trap_no, &sc->trapno);
+ put_user_ex(current->thread.error_code, &sc->err);
+ put_user_ex(regs->ip, &sc->ip);
+ put_user_ex(regs->cs, (unsigned int __user *)&sc->cs);
+ put_user_ex(regs->flags, &sc->flags);
+ put_user_ex(regs->sp, &sc->sp_at_signal);
+ put_user_ex(regs->ss, (unsigned int __user *)&sc->ss);
+
+ put_user_ex(ptr_to_compat(fpstate), &sc->fpstate);
+
+ /* non-iBCS2 extensions.. */
+ put_user_ex(mask, &sc->oldmask);
+ put_user_ex(current->thread.cr2, &sc->cr2);
+ } put_user_catch(err);

return err;
}
@@ -437,13 +459,17 @@ int ia32_setup_frame(int sig, struct k_sigaction *ka,
else
restorer = &frame->retcode;
}
- err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);

- /*
- * These are actually not used anymore, but left because some
- * gdb versions depend on them as a marker.
- */
- err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode);
+ put_user_try {
+ put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
+
+ /*
+ * These are actually not used anymore, but left because some
+ * gdb versions depend on them as a marker.
+ */
+ put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
+ } put_user_catch(err);
+
if (err)
return -EFAULT;

@@ -496,41 +522,40 @@ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
return -EFAULT;

- err |= __put_user(sig, &frame->sig);
- err |= __put_user(ptr_to_compat(&frame->info), &frame->pinfo);
- err |= __put_user(ptr_to_compat(&frame->uc), &frame->puc);
- err |= copy_siginfo_to_user32(&frame->info, info);
- if (err)
- return -EFAULT;
+ put_user_try {
+ put_user_ex(sig, &frame->sig);
+ put_user_ex(ptr_to_compat(&frame->info), &frame->pinfo);
+ put_user_ex(ptr_to_compat(&frame->uc), &frame->puc);
+ err |= copy_siginfo_to_user32(&frame->info, info);

- /* Create the ucontext. */
- if (cpu_has_xsave)
- err |= __put_user(UC_FP_XSTATE, &frame->uc.uc_flags);
- else
- err |= __put_user(0, &frame->uc.uc_flags);
- err |= __put_user(0, &frame->uc.uc_link);
- err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
- err |= __put_user(sas_ss_flags(regs->sp),
- &frame->uc.uc_stack.ss_flags);
- err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
- err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
- regs, set->sig[0]);
- err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
- if (err)
- return -EFAULT;
+ /* Create the ucontext. */
+ if (cpu_has_xsave)
+ put_user_ex(UC_FP_XSTATE, &frame->uc.uc_flags);
+ else
+ put_user_ex(0, &frame->uc.uc_flags);
+ put_user_ex(0, &frame->uc.uc_link);
+ put_user_ex(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+ put_user_ex(sas_ss_flags(regs->sp),
+ &frame->uc.uc_stack.ss_flags);
+ put_user_ex(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+ err |= ia32_setup_sigcontext(&frame->uc.uc_mcontext, fpstate,
+ regs, set->sig[0]);
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+ if (ka->sa.sa_flags & SA_RESTORER)
+ restorer = ka->sa.sa_restorer;
+ else
+ restorer = VDSO32_SYMBOL(current->mm->context.vdso,
+ rt_sigreturn);
+ put_user_ex(ptr_to_compat(restorer), &frame->pretcode);
+
+ /*
+ * Not actually used anymore, but left because some gdb
+ * versions need it.
+ */
+ put_user_ex(*((u64 *)&code), (u64 *)frame->retcode);
+ } put_user_catch(err);

- if (ka->sa.sa_flags & SA_RESTORER)
- restorer = ka->sa.sa_restorer;
- else
- restorer = VDSO32_SYMBOL(current->mm->context.vdso,
- rt_sigreturn);
- err |= __put_user(ptr_to_compat(restorer), &frame->pretcode);
-
- /*
- * Not actually used anymore, but left because some gdb
- * versions need it.
- */
- err |= __put_user(*((u64 *)&code), (u64 *)frame->retcode);
if (err)
return -EFAULT;

--
1.6.0.4

2009-01-24 00:52:14

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [RFC v2 -tip 0/3] x86: reduce fixup of uaccess

Hiroshi Shimamoto wrote:
> ChangeLog v1 -> v2
> - Change framework syntax. Previous version doesn't look easy to read.
> Remove parens from try and add redundant braces as Peter suggested.
> get_user_try {
> get_user_ex(...);
> :
> } get_user_catch(err);
> - Remove double underscores.

Cool, looks a lot nicer this way.

I will try to try it out today.

-hpa

2009-01-24 04:40:26

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [RFC v2 -tip 0/3] x86: reduce fixup of uaccess

Hiroshi Shimamoto wrote:
> This patch series redues fixup code for exceptions of uaccess in signal.
>
> There is a lot of fixup code which is generated by using __{get|put}_user.
> I think that code can be reduced. The concept is that to add uaccess_err in
> thread_info and set it to -EFAULT on exception, finally check this value on
> the last of function.
>
> The code size reductions are below;
> $ size *signal*.o.*
> text data bss dec hex filename
> 4596 0 0 4596 11f4 ia32_signal.o.new
> 6006 0 0 6006 1776 ia32_signal.o.old
> 3583 0 0 3583 dff signal.o.new
> 4540 0 0 4540 11bc signal.o.old
> 3863 0 0 3863 f17 signal32.o.new
> 4876 0 0 4876 130c signal32.o.old
> [ signal32.o means signal.o on 32-bit. ]
>

Applied to tip:x86/uaccess. I haven't tested it much yet, but at least
a visual lookover looks good.

Thanks!

-hpa

--
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel. I don't speak on their behalf.

2009-01-24 07:36:51

by Cyrill Gorcunov

[permalink] [raw]
Subject: Re: [RFC v2 -tip 3/3] x86: ia32_signal: use {get|put}_user_try and catch

[Hiroshi Shimamoto - Fri, Jan 23, 2009 at 03:50:38PM -0800]
| From: Hiroshi Shimamoto <[email protected]>
|
| Impact: use new framework
|
| Use {get|put}_user_try, catch, and _ex in arch/x86/ia32/ia32_signal.c.
|
| Note: this patch contains "WARNING: line over 80 characters", because when
| introducing new block I insert an indent to avoid mistakes by edit.
|
| Signed-off-by: Hiroshi Shimamoto <[email protected]>
| ---
| arch/x86/ia32/ia32_signal.c | 365 +++++++++++++++++++++++--------------------
| 1 files changed, 195 insertions(+), 170 deletions(-)
|
| diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
| index 9dabd00..dd77ac0 100644
| --- a/arch/x86/ia32/ia32_signal.c
| +++ b/arch/x86/ia32/ia32_signal.c
| @@ -46,78 +46,83 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
|
...
| + put_user_try {
| + /* If you change siginfo_t structure, please make sure that
| + this code is fixed accordingly.
| + It should never copy any pad contained in the structure
| + to avoid security leaks, but must copy the generic
| + 3 ints plus the relevant union member. */
| + put_user_ex(from->si_signo, &to->si_signo);
| + put_user_ex(from->si_errno, &to->si_errno);
| + put_user_ex((short)from->si_code, &to->si_code);
| +
| + if (from->si_code < 0) {
| + put_user_ex(from->si_pid, &to->si_pid);
| + put_user_ex(from->si_uid, &to->si_uid);
| + put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
| + } else {
| + /*
| + * First 32bits of unions are always present:
| + * si_pid === si_band === si_tid === si_addr(LS half)
| + */
| + put_user_ex(from->_sifields._pad[0],
| + &to->_sifields._pad[0]);
| + switch (from->si_code >> 16) {
| + case __SI_FAULT >> 16:
| + break;
| + case __SI_CHLD >> 16:
| + put_user_ex(from->si_utime, &to->si_utime);
| + put_user_ex(from->si_stime, &to->si_stime);
| + put_user_ex(from->si_status, &to->si_status);
| + /* FALL THROUGH */
| + default:

Hi Hiroshi,

may I ask why we use default here?

| + case __SI_KILL >> 16:
| + put_user_ex(from->si_uid, &to->si_uid);
| + break;
| + case __SI_POLL >> 16:
| + put_user_ex(from->si_fd, &to->si_fd);
| + break;
| + case __SI_TIMER >> 16:
| + put_user_ex(from->si_overrun, &to->si_overrun);
| + put_user_ex(ptr_to_compat(from->si_ptr),
| + &to->si_ptr);
| + break;
| + /* This is not generated by the kernel as of now. */
| + case __SI_RT >> 16:
| + case __SI_MESGQ >> 16:
| + put_user_ex(from->si_uid, &to->si_uid);
| + put_user_ex(from->si_int, &to->si_int);
| + break;
| + }
| }
| - }
| + } put_user_catch(err);
| +
| return err;
| }
|
...

- Cyrill -

2009-01-26 18:31:18

by Hiroshi Shimamoto

[permalink] [raw]
Subject: Re: [RFC v2 -tip 3/3] x86: ia32_signal: use {get|put}_user_try and catch

Cyrill Gorcunov wrote:
> [Hiroshi Shimamoto - Fri, Jan 23, 2009 at 03:50:38PM -0800]
> | From: Hiroshi Shimamoto <[email protected]>
> |
> | Impact: use new framework
> |
> | Use {get|put}_user_try, catch, and _ex in arch/x86/ia32/ia32_signal.c.
> |
> | Note: this patch contains "WARNING: line over 80 characters", because when
> | introducing new block I insert an indent to avoid mistakes by edit.
> |
> | Signed-off-by: Hiroshi Shimamoto <[email protected]>
> | ---
> | arch/x86/ia32/ia32_signal.c | 365 +++++++++++++++++++++++--------------------
> | 1 files changed, 195 insertions(+), 170 deletions(-)
> |
> | diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
> | index 9dabd00..dd77ac0 100644
> | --- a/arch/x86/ia32/ia32_signal.c
> | +++ b/arch/x86/ia32/ia32_signal.c
> | @@ -46,78 +46,83 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
> |
> ...
> | + put_user_try {
> | + /* If you change siginfo_t structure, please make sure that
> | + this code is fixed accordingly.
> | + It should never copy any pad contained in the structure
> | + to avoid security leaks, but must copy the generic
> | + 3 ints plus the relevant union member. */
> | + put_user_ex(from->si_signo, &to->si_signo);
> | + put_user_ex(from->si_errno, &to->si_errno);
> | + put_user_ex((short)from->si_code, &to->si_code);
> | +
> | + if (from->si_code < 0) {
> | + put_user_ex(from->si_pid, &to->si_pid);
> | + put_user_ex(from->si_uid, &to->si_uid);
> | + put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
> | + } else {
> | + /*
> | + * First 32bits of unions are always present:
> | + * si_pid === si_band === si_tid === si_addr(LS half)
> | + */
> | + put_user_ex(from->_sifields._pad[0],
> | + &to->_sifields._pad[0]);
> | + switch (from->si_code >> 16) {
> | + case __SI_FAULT >> 16:
> | + break;
> | + case __SI_CHLD >> 16:
> | + put_user_ex(from->si_utime, &to->si_utime);
> | + put_user_ex(from->si_stime, &to->si_stime);
> | + put_user_ex(from->si_status, &to->si_status);
> | + /* FALL THROUGH */
> | + default:
>
> Hi Hiroshi,

Hi Cyrill,

>
> may I ask why we use default here?

I don't know:) Hm, it looks old code.
arch/i386/kernel/signal.c in 2.4 has similar code.

I guess this code didn't change when copy_siginfo_to_user() was moved
from arch/i386/kernel/signal.c to kernel/signal.c.

Should we change this like copy_siginfo_tu_user() in kernel/signal.c?
Copying si_pid was added in kernel/signal.c.

BTW, it seems same __ST_KILL and default.

Thanks,
Hiroshi

>
> | + case __SI_KILL >> 16:
> | + put_user_ex(from->si_uid, &to->si_uid);
> | + break;
> | + case __SI_POLL >> 16:
> | + put_user_ex(from->si_fd, &to->si_fd);
> | + break;
> | + case __SI_TIMER >> 16:
> | + put_user_ex(from->si_overrun, &to->si_overrun);
> | + put_user_ex(ptr_to_compat(from->si_ptr),
> | + &to->si_ptr);
> | + break;
> | + /* This is not generated by the kernel as of now. */
> | + case __SI_RT >> 16:
> | + case __SI_MESGQ >> 16:
> | + put_user_ex(from->si_uid, &to->si_uid);
> | + put_user_ex(from->si_int, &to->si_int);
> | + break;
> | + }
> | }
> | - }
> | + } put_user_catch(err);
> | +
> | return err;
> | }
> |
> ...
>
> - Cyrill -
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
>

2009-01-26 18:57:01

by Cyrill Gorcunov

[permalink] [raw]
Subject: Re: [RFC v2 -tip 3/3] x86: ia32_signal: use {get|put}_user_try and catch

[Hiroshi Shimamoto - Mon, Jan 26, 2009 at 10:31:03AM -0800]
| Cyrill Gorcunov wrote:
| > [Hiroshi Shimamoto - Fri, Jan 23, 2009 at 03:50:38PM -0800]
| > | From: Hiroshi Shimamoto <[email protected]>
| > |
| > | Impact: use new framework
| > |
| > | Use {get|put}_user_try, catch, and _ex in arch/x86/ia32/ia32_signal.c.
| > |
| > | Note: this patch contains "WARNING: line over 80 characters", because when
| > | introducing new block I insert an indent to avoid mistakes by edit.
| > |
| > | Signed-off-by: Hiroshi Shimamoto <[email protected]>
| > | ---
| > | arch/x86/ia32/ia32_signal.c | 365 +++++++++++++++++++++++--------------------
| > | 1 files changed, 195 insertions(+), 170 deletions(-)
| > |
| > | diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c
| > | index 9dabd00..dd77ac0 100644
| > | --- a/arch/x86/ia32/ia32_signal.c
| > | +++ b/arch/x86/ia32/ia32_signal.c
| > | @@ -46,78 +46,83 @@ void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
| > |
| > ...
| > | + put_user_try {
| > | + /* If you change siginfo_t structure, please make sure that
| > | + this code is fixed accordingly.
| > | + It should never copy any pad contained in the structure
| > | + to avoid security leaks, but must copy the generic
| > | + 3 ints plus the relevant union member. */
| > | + put_user_ex(from->si_signo, &to->si_signo);
| > | + put_user_ex(from->si_errno, &to->si_errno);
| > | + put_user_ex((short)from->si_code, &to->si_code);
| > | +
| > | + if (from->si_code < 0) {
| > | + put_user_ex(from->si_pid, &to->si_pid);
| > | + put_user_ex(from->si_uid, &to->si_uid);
| > | + put_user_ex(ptr_to_compat(from->si_ptr), &to->si_ptr);
| > | + } else {
| > | + /*
| > | + * First 32bits of unions are always present:
| > | + * si_pid === si_band === si_tid === si_addr(LS half)
| > | + */
| > | + put_user_ex(from->_sifields._pad[0],
| > | + &to->_sifields._pad[0]);
| > | + switch (from->si_code >> 16) {
| > | + case __SI_FAULT >> 16:
| > | + break;
| > | + case __SI_CHLD >> 16:
| > | + put_user_ex(from->si_utime, &to->si_utime);
| > | + put_user_ex(from->si_stime, &to->si_stime);
| > | + put_user_ex(from->si_status, &to->si_status);
| > | + /* FALL THROUGH */
| > | + default:
| >
| > Hi Hiroshi,
|
| Hi Cyrill,
|
| >
| > may I ask why we use default here?
|
| I don't know:) Hm, it looks old code.
| arch/i386/kernel/signal.c in 2.4 has similar code.
|
| I guess this code didn't change when copy_siginfo_to_user() was moved
| from arch/i386/kernel/signal.c to kernel/signal.c.
|
| Should we change this like copy_siginfo_tu_user() in kernel/signal.c?
| Copying si_pid was added in kernel/signal.c.
|
| BTW, it seems same __ST_KILL and default.

Hiroshi, to be fair -- I just don't know what the
right solution would be ;-) I just noticed that
default: here a bit useless since we do 'testing'
the (from->si_code >> 16) after default: anyway.

So choose one /since I'm not really familiar with
process management in kernel/ :)

-- Cyrill --