Commit dd198ce7 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace

Pull namespace updates from Eric Biederman:
 "Life has been busy and I have not gotten half as much done this round
  as I would have liked. I delayed it so that a minor conflict
  resolution with the mips tree could spend a little time in linux-next
  before I sent this pull request.

  This includes two long delayed user namespace changes from Kirill
  Tkhai. It also includes a very useful change from Serge Hallyn that
  allows the security capability attribute to be used inside of user
  namespaces. The practical effect of this is people can now untar
  tarballs and install rpms in user namespaces. It had been suggested to
  generalize this and encode some of the namespace information
  information in the xattr name. Upon close inspection that makes the
  things that should be hard easy and the things that should be easy
  more expensive.

  Then there is my bugfix/cleanup for signal injection that removes the
  magic encoding of the siginfo union member from the kernel internal
  si_code. The mips folks reported the case where I had used FPE_FIXME
  me is impossible so I have remove FPE_FIXME from mips, while at the
  same time including a return statement in that case to keep gcc from
  complaining about unitialized variables.

  I almost finished the work to get make copy_siginfo_to_user a trivial
  copy to user. The code is available at:

     git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace.git neuter-copy_siginfo_to_user-v3

  But I did not have time/energy to get the code posted and reviewed
  before the merge window opened.

  I was able to see that the security excuse for just copying fields
  that we know are initialized doesn't work in practice there are buggy
  initializations that don't initialize the proper fields in siginfo. So
  we still sometimes copy unitialized data to userspace"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/user-namespace:
  Introduce v3 namespaced file capabilities
  mips/signal: In force_fcr31_sig return in the impossible case
  signal: Remove kernel interal si_code magic
  fcntl: Don't use ambiguous SIG_POLL si_codes
  prctl: Allow local CAP_SYS_ADMIN changing exe_file
  security: Use user_namespace::level to avoid redundant iterations in cap_capable()
  userns,pidns: Verify the userns for new pid namespaces
  signal/testing: Don't look for __SI_FAULT in userspace
  signal/mips: Document a conflict with SI_USER with SIGFPE
  signal/sparc: Document a conflict with SI_USER with SIGFPE
  signal/ia64: Document a conflict with SI_USER with SIGFPE
  signal/alpha: Document a conflict with SI_USER for SIGTRAP
parents 89fd915c 076a9bca
...@@ -6,4 +6,18 @@ ...@@ -6,4 +6,18 @@
#include <asm-generic/siginfo.h> #include <asm-generic/siginfo.h>
/*
* SIGFPE si_codes
*/
#ifdef __KERNEL__
#define FPE_FIXME 0 /* Broken dup of SI_USER */
#endif /* __KERNEL__ */
/*
* SIGTRAP si_codes
*/
#ifdef __KERNEL__
#define TRAP_FIXME 0 /* Broken dup of SI_USER */
#endif /* __KERNEL__ */
#endif #endif
...@@ -280,7 +280,7 @@ do_entIF(unsigned long type, struct pt_regs *regs) ...@@ -280,7 +280,7 @@ do_entIF(unsigned long type, struct pt_regs *regs)
case 1: /* bugcheck */ case 1: /* bugcheck */
info.si_signo = SIGTRAP; info.si_signo = SIGTRAP;
info.si_errno = 0; info.si_errno = 0;
info.si_code = __SI_FAULT; info.si_code = TRAP_FIXME;
info.si_addr = (void __user *) regs->pc; info.si_addr = (void __user *) regs->pc;
info.si_trapno = 0; info.si_trapno = 0;
send_sig_info(SIGTRAP, &info, current); send_sig_info(SIGTRAP, &info, current);
...@@ -320,7 +320,7 @@ do_entIF(unsigned long type, struct pt_regs *regs) ...@@ -320,7 +320,7 @@ do_entIF(unsigned long type, struct pt_regs *regs)
break; break;
case GEN_ROPRAND: case GEN_ROPRAND:
signo = SIGFPE; signo = SIGFPE;
code = __SI_FAULT; code = FPE_FIXME;
break; break;
case GEN_DECOVF: case GEN_DECOVF:
...@@ -342,7 +342,7 @@ do_entIF(unsigned long type, struct pt_regs *regs) ...@@ -342,7 +342,7 @@ do_entIF(unsigned long type, struct pt_regs *regs)
case GEN_SUBRNG7: case GEN_SUBRNG7:
default: default:
signo = SIGTRAP; signo = SIGTRAP;
code = __SI_FAULT; code = TRAP_FIXME;
break; break;
} }
......
...@@ -142,25 +142,25 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) ...@@ -142,25 +142,25 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
*/ */
err = __put_user(from->si_signo, &to->si_signo); err = __put_user(from->si_signo, &to->si_signo);
err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user(from->si_errno, &to->si_errno);
err |= __put_user((short)from->si_code, &to->si_code); err |= __put_user(from->si_code, &to->si_code);
if (from->si_code < 0) if (from->si_code < 0)
err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad,
SI_PAD_SIZE); SI_PAD_SIZE);
else switch (from->si_code & __SI_MASK) { else switch (siginfo_layout(from->si_signo, from->si_code)) {
case __SI_KILL: case SIL_KILL:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
break; break;
case __SI_TIMER: case SIL_TIMER:
err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_tid, &to->si_tid);
err |= __put_user(from->si_overrun, &to->si_overrun); err |= __put_user(from->si_overrun, &to->si_overrun);
err |= __put_user(from->si_int, &to->si_int); err |= __put_user(from->si_int, &to->si_int);
break; break;
case __SI_POLL: case SIL_POLL:
err |= __put_user(from->si_band, &to->si_band); err |= __put_user(from->si_band, &to->si_band);
err |= __put_user(from->si_fd, &to->si_fd); err |= __put_user(from->si_fd, &to->si_fd);
break; break;
case __SI_FAULT: case SIL_FAULT:
err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr, err |= __put_user((compat_uptr_t)(unsigned long)from->si_addr,
&to->si_addr); &to->si_addr);
#ifdef BUS_MCEERR_AO #ifdef BUS_MCEERR_AO
...@@ -173,29 +173,24 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) ...@@ -173,29 +173,24 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb); err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
#endif #endif
break; break;
case __SI_CHLD: case SIL_CHLD:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_status, &to->si_status); err |= __put_user(from->si_status, &to->si_status);
err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_stime, &to->si_stime);
break; break;
case __SI_RT: /* This is not generated by the kernel as of now. */ case SIL_RT:
case __SI_MESGQ: /* But this is */
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_int, &to->si_int); err |= __put_user(from->si_int, &to->si_int);
break; break;
case __SI_SYS: case SIL_SYS:
err |= __put_user((compat_uptr_t)(unsigned long) err |= __put_user((compat_uptr_t)(unsigned long)
from->si_call_addr, &to->si_call_addr); from->si_call_addr, &to->si_call_addr);
err |= __put_user(from->si_syscall, &to->si_syscall); err |= __put_user(from->si_syscall, &to->si_syscall);
err |= __put_user(from->si_arch, &to->si_arch); err |= __put_user(from->si_arch, &to->si_arch);
break; break;
default: /* this is just in case for now ... */
err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid);
break;
} }
return err; return err;
} }
......
...@@ -14,28 +14,36 @@ ...@@ -14,28 +14,36 @@
#define si_uid16 _sifields._kill._uid #define si_uid16 _sifields._kill._uid
#define ILL_ILLPARAOP (__SI_FAULT|2) /* illegal opcode combine ********** */ #define ILL_ILLPARAOP 2 /* illegal opcode combine ********** */
#define ILL_ILLEXCPT (__SI_FAULT|4) /* unrecoverable exception ********** */ #define ILL_ILLEXCPT 4 /* unrecoverable exception ********** */
#define ILL_CPLB_VI (__SI_FAULT|9) /* D/I CPLB protect violation ******** */ #define ILL_CPLB_VI 9 /* D/I CPLB protect violation ******** */
#define ILL_CPLB_MISS (__SI_FAULT|10) /* D/I CPLB miss ******** */ #define ILL_CPLB_MISS 10 /* D/I CPLB miss ******** */
#define ILL_CPLB_MULHIT (__SI_FAULT|11) /* D/I CPLB multiple hit ******** */ #define ILL_CPLB_MULHIT 11 /* D/I CPLB multiple hit ******** */
#undef NSIGILL
#define NSIGILL 11
/* /*
* SIGBUS si_codes * SIGBUS si_codes
*/ */
#define BUS_OPFETCH (__SI_FAULT|4) /* error from instruction fetch ******** */ #define BUS_OPFETCH 4 /* error from instruction fetch ******** */
#undef NSIGBUS
#define NSIGBUS 4
/* /*
* SIGTRAP si_codes * SIGTRAP si_codes
*/ */
#define TRAP_STEP (__SI_FAULT|1) /* single-step breakpoint************* */ #define TRAP_STEP 1 /* single-step breakpoint************* */
#define TRAP_TRACEFLOW (__SI_FAULT|2) /* trace buffer overflow ************* */ #define TRAP_TRACEFLOW 2 /* trace buffer overflow ************* */
#define TRAP_WATCHPT (__SI_FAULT|3) /* watchpoint match ************* */ #define TRAP_WATCHPT 3 /* watchpoint match ************* */
#define TRAP_ILLTRAP (__SI_FAULT|4) /* illegal trap ************* */ #define TRAP_ILLTRAP 4 /* illegal trap ************* */
#undef NSIGTRAP
#define NSIGTRAP 4
/* /*
* SIGSEGV si_codes * SIGSEGV si_codes
*/ */
#define SEGV_STACKFLOW (__SI_FAULT|3) /* stack overflow */ #define SEGV_STACKFLOW 3 /* stack overflow */
#undef NSIGSEGV
#define NSIGSEGV 3
#endif /* _UAPI_BFIN_SIGINFO_H */ #endif /* _UAPI_BFIN_SIGINFO_H */
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <asm-generic/siginfo.h> #include <asm-generic/siginfo.h>
#define FPE_MDAOVF (__SI_FAULT|9) /* media overflow */ #define FPE_MDAOVF 9 /* media overflow */
#undef NSIGFPE #undef NSIGFPE
#define NSIGFPE 9 #define NSIGFPE 9
......
...@@ -98,27 +98,30 @@ typedef struct siginfo { ...@@ -98,27 +98,30 @@ typedef struct siginfo {
/* /*
* SIGILL si_codes * SIGILL si_codes
*/ */
#define ILL_BADIADDR (__SI_FAULT|9) /* unimplemented instruction address */ #define ILL_BADIADDR 9 /* unimplemented instruction address */
#define __ILL_BREAK (__SI_FAULT|10) /* illegal break */ #define __ILL_BREAK 10 /* illegal break */
#define __ILL_BNDMOD (__SI_FAULT|11) /* bundle-update (modification) in progress */ #define __ILL_BNDMOD 11 /* bundle-update (modification) in progress */
#undef NSIGILL #undef NSIGILL
#define NSIGILL 11 #define NSIGILL 11
/* /*
* SIGFPE si_codes * SIGFPE si_codes
*/ */
#define __FPE_DECOVF (__SI_FAULT|9) /* decimal overflow */ #ifdef __KERNEL__
#define __FPE_DECDIV (__SI_FAULT|10) /* decimal division by zero */ #define FPE_FIXME 0 /* Broken dup of SI_USER */
#define __FPE_DECERR (__SI_FAULT|11) /* packed decimal error */ #endif /* __KERNEL__ */
#define __FPE_INVASC (__SI_FAULT|12) /* invalid ASCII digit */ #define __FPE_DECOVF 9 /* decimal overflow */
#define __FPE_INVDEC (__SI_FAULT|13) /* invalid decimal digit */ #define __FPE_DECDIV 10 /* decimal division by zero */
#define __FPE_DECERR 11 /* packed decimal error */
#define __FPE_INVASC 12 /* invalid ASCII digit */
#define __FPE_INVDEC 13 /* invalid decimal digit */
#undef NSIGFPE #undef NSIGFPE
#define NSIGFPE 13 #define NSIGFPE 13
/* /*
* SIGSEGV si_codes * SIGSEGV si_codes
*/ */
#define __SEGV_PSTKOVF (__SI_FAULT|4) /* paragraph stack overflow */ #define __SEGV_PSTKOVF 4 /* paragraph stack overflow */
#undef NSIGSEGV #undef NSIGSEGV
#define NSIGSEGV 4 #define NSIGSEGV 4
......
...@@ -124,31 +124,30 @@ copy_siginfo_to_user (siginfo_t __user *to, const siginfo_t *from) ...@@ -124,31 +124,30 @@ copy_siginfo_to_user (siginfo_t __user *to, const siginfo_t *from)
*/ */
err = __put_user(from->si_signo, &to->si_signo); err = __put_user(from->si_signo, &to->si_signo);
err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user(from->si_errno, &to->si_errno);
err |= __put_user((short)from->si_code, &to->si_code); err |= __put_user(from->si_code, &to->si_code);
switch (from->si_code >> 16) { switch (siginfo_layout(from->si_signo, from->si_code)) {
case __SI_FAULT >> 16: case SIL_FAULT:
err |= __put_user(from->si_flags, &to->si_flags); err |= __put_user(from->si_flags, &to->si_flags);
err |= __put_user(from->si_isr, &to->si_isr); err |= __put_user(from->si_isr, &to->si_isr);
case __SI_POLL >> 16: case SIL_POLL:
err |= __put_user(from->si_addr, &to->si_addr); err |= __put_user(from->si_addr, &to->si_addr);
err |= __put_user(from->si_imm, &to->si_imm); err |= __put_user(from->si_imm, &to->si_imm);
break; break;
case __SI_TIMER >> 16: case SIL_TIMER:
err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_tid, &to->si_tid);
err |= __put_user(from->si_overrun, &to->si_overrun); err |= __put_user(from->si_overrun, &to->si_overrun);
err |= __put_user(from->si_ptr, &to->si_ptr); err |= __put_user(from->si_ptr, &to->si_ptr);
break; break;
case __SI_RT >> 16: /* Not generated by the kernel as of now. */ case SIL_RT:
case __SI_MESGQ >> 16:
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_ptr, &to->si_ptr); err |= __put_user(from->si_ptr, &to->si_ptr);
break; break;
case __SI_CHLD >> 16: case SIL_CHLD:
err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_stime, &to->si_stime);
err |= __put_user(from->si_status, &to->si_status); err |= __put_user(from->si_status, &to->si_status);
default: case SIL_KILL:
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
break; break;
......
...@@ -349,7 +349,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) ...@@ -349,7 +349,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
} }
siginfo.si_signo = SIGFPE; siginfo.si_signo = SIGFPE;
siginfo.si_errno = 0; siginfo.si_errno = 0;
siginfo.si_code = __SI_FAULT; /* default code */ siginfo.si_code = FPE_FIXME; /* default code */
siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri);
if (isr & 0x11) { if (isr & 0x11) {
siginfo.si_code = FPE_FLTINV; siginfo.si_code = FPE_FLTINV;
...@@ -373,7 +373,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr) ...@@ -373,7 +373,7 @@ handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigned long isr)
/* raise exception */ /* raise exception */
siginfo.si_signo = SIGFPE; siginfo.si_signo = SIGFPE;
siginfo.si_errno = 0; siginfo.si_errno = 0;
siginfo.si_code = __SI_FAULT; /* default code */ siginfo.si_code = FPE_FIXME; /* default code */
siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_addr = (void __user *) (regs->cr_iip + ia64_psr(regs)->ri);
if (isr & 0x880) { if (isr & 0x880) {
siginfo.si_code = FPE_FLTOVF; siginfo.si_code = FPE_FLTOVF;
......
...@@ -120,7 +120,7 @@ typedef struct siginfo { ...@@ -120,7 +120,7 @@ typedef struct siginfo {
#undef SI_TIMER #undef SI_TIMER
#undef SI_MESGQ #undef SI_MESGQ
#define SI_ASYNCIO -2 /* sent by AIO completion */ #define SI_ASYNCIO -2 /* sent by AIO completion */
#define SI_TIMER __SI_CODE(__SI_TIMER, -3) /* sent by timer expiration */ #define SI_TIMER -3 /* sent by timer expiration */
#define SI_MESGQ __SI_CODE(__SI_MESGQ, -4) /* sent by real time mesq state change */ #define SI_MESGQ -4 /* sent by real time mesq state change */
#endif /* _UAPI_ASM_SIGINFO_H */ #endif /* _UAPI_ASM_SIGINFO_H */
...@@ -93,38 +93,37 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) ...@@ -93,38 +93,37 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
at the same time. */ at the same time. */
err = __put_user(from->si_signo, &to->si_signo); err = __put_user(from->si_signo, &to->si_signo);
err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user(from->si_errno, &to->si_errno);
err |= __put_user((short)from->si_code, &to->si_code); err |= __put_user(from->si_code, &to->si_code);
if (from->si_code < 0) if (from->si_code < 0)
err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
else { else {
switch (from->si_code >> 16) { switch (siginfo_layout(from->si_signo, from->si_code)) {
case __SI_TIMER >> 16: case SIL_TIMER:
err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_tid, &to->si_tid);
err |= __put_user(from->si_overrun, &to->si_overrun); err |= __put_user(from->si_overrun, &to->si_overrun);
err |= __put_user(from->si_int, &to->si_int); err |= __put_user(from->si_int, &to->si_int);
break; break;
case __SI_CHLD >> 16: case SIL_CHLD:
err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_stime, &to->si_stime);
err |= __put_user(from->si_status, &to->si_status); err |= __put_user(from->si_status, &to->si_status);
default: case SIL_KILL:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
break; break;
case __SI_FAULT >> 16: case SIL_FAULT:
err |= __put_user((unsigned long)from->si_addr, &to->si_addr); err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
break; break;
case __SI_POLL >> 16: case SIL_POLL:
err |= __put_user(from->si_band, &to->si_band); err |= __put_user(from->si_band, &to->si_band);
err |= __put_user(from->si_fd, &to->si_fd); err |= __put_user(from->si_fd, &to->si_fd);
break; break;
case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case SIL_RT:
case __SI_MESGQ >> 16:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_int, &to->si_int); err |= __put_user(from->si_int, &to->si_int);
break; break;
case __SI_SYS >> 16: case SIL_SYS:
err |= __copy_to_user(&to->si_call_addr, &from->si_call_addr, err |= __copy_to_user(&to->si_call_addr, &from->si_call_addr,
sizeof(compat_uptr_t)); sizeof(compat_uptr_t));
err |= __put_user(from->si_syscall, &to->si_syscall); err |= __put_user(from->si_syscall, &to->si_syscall);
......
...@@ -735,7 +735,7 @@ void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr, ...@@ -735,7 +735,7 @@ void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
else if (fcr31 & FPU_CSR_INE_X) else if (fcr31 & FPU_CSR_INE_X)
si.si_code = FPE_FLTRES; si.si_code = FPE_FLTRES;
else else
si.si_code = __SI_FAULT; return; /* Broken hardware? */
force_sig_info(SIGFPE, &si, tsk); force_sig_info(SIGFPE, &si, tsk);
} }
......
...@@ -290,25 +290,25 @@ copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from) ...@@ -290,25 +290,25 @@ copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from)
if (to->si_code < 0) if (to->si_code < 0)
err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
else { else {
switch (to->si_code >> 16) { switch (siginfo_layout(to->si_signo, to->si_code)) {
case __SI_CHLD >> 16: case SIL_CHLD:
err |= __get_user(to->si_utime, &from->si_utime); err |= __get_user(to->si_utime, &from->si_utime);
err |= __get_user(to->si_stime, &from->si_stime); err |= __get_user(to->si_stime, &from->si_stime);
err |= __get_user(to->si_status, &from->si_status); err |= __get_user(to->si_status, &from->si_status);
default: default:
case SIL_KILL:
err |= __get_user(to->si_pid, &from->si_pid); err |= __get_user(to->si_pid, &from->si_pid);
err |= __get_user(to->si_uid, &from->si_uid); err |= __get_user(to->si_uid, &from->si_uid);
break; break;
case __SI_FAULT >> 16: case SIL_FAULT:
err |= __get_user(addr, &from->si_addr); err |= __get_user(addr, &from->si_addr);
to->si_addr = compat_ptr(addr); to->si_addr = compat_ptr(addr);
break; break;
case __SI_POLL >> 16: case SIL_POLL:
err |= __get_user(to->si_band, &from->si_band); err |= __get_user(to->si_band, &from->si_band);
err |= __get_user(to->si_fd, &from->si_fd); err |= __get_user(to->si_fd, &from->si_fd);
break; break;
case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case SIL_RT:
case __SI_MESGQ >> 16:
err |= __get_user(to->si_pid, &from->si_pid); err |= __get_user(to->si_pid, &from->si_pid);
err |= __get_user(to->si_uid, &from->si_uid); err |= __get_user(to->si_uid, &from->si_uid);
err |= __get_user(to->si_int, &from->si_int); err |= __get_user(to->si_int, &from->si_int);
...@@ -337,41 +337,40 @@ copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from) ...@@ -337,41 +337,40 @@ copy_siginfo_to_user32 (compat_siginfo_t __user *to, const siginfo_t *from)
at the same time. */ at the same time. */
err = __put_user(from->si_signo, &to->si_signo); err = __put_user(from->si_signo, &to->si_signo);
err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user(from->si_errno, &to->si_errno);
err |= __put_user((short)from->si_code, &to->si_code); err |= __put_user(from->si_code, &to->si_code);
if (from->si_code < 0) if (from->si_code < 0)
err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
else { else {
switch (from->si_code >> 16) { switch (siginfo_layout(from->si_signo, from->si_code)) {
case __SI_CHLD >> 16: case SIL_CHLD:
err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_stime, &to->si_stime);
err |= __put_user(from->si_status, &to->si_status); err |= __put_user(from->si_status, &to->si_status);
default: case SIL_KILL:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
break; break;
case __SI_FAULT >> 16: case SIL_FAULT:
addr = ptr_to_compat(from->si_addr); addr = ptr_to_compat(from->si_addr);
err |= __put_user(addr, &to->si_addr); err |= __put_user(addr, &to->si_addr);
break; break;
case __SI_POLL >> 16: case SIL_POLL:
err |= __put_user(from->si_band, &to->si_band); err |= __put_user(from->si_band, &to->si_band);
err |= __put_user(from->si_fd, &to->si_fd); err |= __put_user(from->si_fd, &to->si_fd);
break; break;
case __SI_TIMER >> 16: case SIL_TIMER:
err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_tid, &to->si_tid);
err |= __put_user(from->si_overrun, &to->si_overrun); err |= __put_user(from->si_overrun, &to->si_overrun);
val = (compat_int_t)from->si_int; val = (compat_int_t)from->si_int;
err |= __put_user(val, &to->si_int); err |= __put_user(val, &to->si_int);
break; break;
case __SI_RT >> 16: /* Not generated by the kernel as of now. */ case SIL_RT:
case __SI_MESGQ >> 16:
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
val = (compat_int_t)from->si_int; val = (compat_int_t)from->si_int;
err |= __put_user(val, &to->si_int); err |= __put_user(val, &to->si_int);
break; break;
case __SI_SYS >> 16: case SIL_SYS:
err |= __put_user(ptr_to_compat(from->si_call_addr), &to->si_call_addr); err |= __put_user(ptr_to_compat(from->si_call_addr), &to->si_call_addr);
err |= __put_user(from->si_syscall, &to->si_syscall); err |= __put_user(from->si_syscall, &to->si_syscall);
err |= __put_user(from->si_arch, &to->si_arch); err |= __put_user(from->si_arch, &to->si_arch);
......
...@@ -913,42 +913,40 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s) ...@@ -913,42 +913,40 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *d, const siginfo_t *s)
*/ */
err = __put_user(s->si_signo, &d->si_signo); err = __put_user(s->si_signo, &d->si_signo);
err |= __put_user(s->si_errno, &d->si_errno); err |= __put_user(s->si_errno, &d->si_errno);
err |= __put_user((short)s->si_code, &d->si_code); err |= __put_user(s->si_code, &d->si_code);
if (s->si_code < 0) if (s->si_code < 0)
err |= __copy_to_user(&d->_sifields._pad, &s->_sifields._pad, err |= __copy_to_user(&d->_sifields._pad, &s->_sifields._pad,
SI_PAD_SIZE32); SI_PAD_SIZE32);
else switch(s->si_code >> 16) { else switch(siginfo_layout(s->si_signo, s->si_code)) {
case __SI_CHLD >> 16: case SIL_CHLD:
err |= __put_user(s->si_pid, &d->si_pid); err |= __put_user(s->si_pid, &d->si_pid);
err |= __put_user(s->si_uid, &d->si_uid); err |= __put_user(s->si_uid, &d->si_uid);
err |= __put_user(s->si_utime, &d->si_utime); err |= __put_user(s->si_utime, &d->si_utime);
err |= __put_user(s->si_stime, &d->si_stime); err |= __put_user(s->si_stime, &d->si_stime);
err |= __put_user(s->si_status, &d->si_status); err |= __put_user(s->si_status, &d->si_status);
break; break;
case __SI_FAULT >> 16: case SIL_FAULT:
err |= __put_user((unsigned int)(unsigned long)s->si_addr, err |= __put_user((unsigned int)(unsigned long)s->si_addr,
&d->si_addr); &d->si_addr);
break; break;
case __SI_POLL >> 16: case SIL_POLL:
err |= __put_user(s->si_band, &d->si_band); err |= __put_user(s->si_band, &d->si_band);
err |= __put_user(s->si_fd, &d->si_fd); err |= __put_user(s->si_fd, &d->si_fd);
break; break;
case __SI_TIMER >> 16: case SIL_TIMER:
err |= __put_user(s->si_tid, &d->si_tid); err |= __put_user(s->si_tid, &d->si_tid);
err |= __put_user(s->si_overrun, &d->si_overrun); err |= __put_user(s->si_overrun, &d->si_overrun);
err |= __put_user(s->si_int, &d->si_int); err |= __put_user(s->si_int, &d->si_int);
break; break;
case __SI_SYS >> 16: case SIL_SYS:
err |= __put_user(ptr_to_compat(s->si_call_addr), &d->si_call_addr); err |= __put_user(ptr_to_compat(s->si_call_addr), &d->si_call_addr);
err |= __put_user(s->si_syscall, &d->si_syscall); err |= __put_user(s->si_syscall, &d->si_syscall);
err |= __put_user(s->si_arch, &d->si_arch); err |= __put_user(s->si_arch, &d->si_arch);
break; break;
case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case SIL_RT:
case __SI_MESGQ >> 16:
err |= __put_user(s->si_int, &d->si_int); err |= __put_user(s->si_int, &d->si_int);
/* fallthrough */ /* fallthrough */
case __SI_KILL >> 16: case SIL_KILL:
default:
err |= __put_user(s->si_pid, &d->si_pid); err |= __put_user(s->si_pid, &d->si_pid);
err |= __put_user(s->si_uid, &d->si_uid); err |= __put_user(s->si_uid, &d->si_uid);
break; break;
......
...@@ -75,35 +75,34 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) ...@@ -75,35 +75,34 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
at the same time. */ at the same time. */
err = __put_user(from->si_signo, &to->si_signo); err = __put_user(from->si_signo, &to->si_signo);
err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user(from->si_errno, &to->si_errno);
err |= __put_user((short)from->si_code, &to->si_code); err |= __put_user(from->si_code, &to->si_code);
if (from->si_code < 0) if (from->si_code < 0)
err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
else { else {
switch (from->si_code >> 16) { switch (siginfo_layout(from->si_signo, from->si_code)) {
case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case SIL_RT:
case __SI_MESGQ >> 16:
err |= __put_user(from->si_int, &to->si_int); err |= __put_user(from->si_int, &to->si_int);
/* fallthrough */ /* fallthrough */
case __SI_KILL >> 16: case SIL_KILL:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
break; break;
case __SI_CHLD >> 16: case SIL_CHLD:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_stime, &to->si_stime);
err |= __put_user(from->si_status, &to->si_status); err |= __put_user(from->si_status, &to->si_status);
break; break;
case __SI_FAULT >> 16: case SIL_FAULT:
err |= __put_user((unsigned long) from->si_addr, err |= __put_user((unsigned long) from->si_addr,
&to->si_addr); &to->si_addr);
break; break;
case __SI_POLL >> 16: case SIL_POLL:
err |= __put_user(from->si_band, &to->si_band); err |= __put_user(from->si_band, &to->si_band);
err |= __put_user(from->si_fd, &to->si_fd); err |= __put_user(from->si_fd, &to->si_fd);
break; break;
case __SI_TIMER >> 16: case SIL_TIMER:
err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_tid, &to->si_tid);
err |= __put_user(from->si_overrun, &to->si_overrun); err |= __put_user(from->si_overrun, &to->si_overrun);
err |= __put_user(from->si_int, &to->si_int); err |= __put_user(from->si_int, &to->si_int);
...@@ -127,32 +126,31 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) ...@@ -127,32 +126,31 @@ int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from)
if (to->si_code < 0) if (to->si_code < 0)
err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
else { else {
switch (to->si_code >> 16) { switch (siginfo_layout(to->si_signo, to->si_code)) {
case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case SIL_RT:
case __SI_MESGQ >> 16:
err |= __get_user(to->si_int, &from->si_int); err |= __get_user(to->si_int, &from->si_int);
/* fallthrough */ /* fallthrough */
case __SI_KILL >> 16: case SIL_KILL:
err |= __get_user(to->si_pid, &from->si_pid); err |= __get_user(to->si_pid, &from->si_pid);
err |= __get_user(to->si_uid, &from->si_uid); err |= __get_user(to->si_uid, &from->si_uid);
break; break;
case __SI_CHLD >> 16: case SIL_CHLD:
err |= __get_user(to->si_pid, &from->si_pid); err |= __get_user(to->si_pid, &from->si_pid);
err |= __get_user(to->si_uid, &from->si_uid); err |= __get_user(to->si_uid, &from->si_uid);
err |= __get_user(to->si_utime, &from->si_utime); err |= __get_user(to->si_utime, &from->si_utime);
err |= __get_user(to->si_stime, &from->si_stime); err |= __get_user(to->si_stime, &from->si_stime);
err |= __get_user(to->si_status, &from->si_status); err |= __get_user(to->si_status, &from->si_status);
break; break;
case __SI_FAULT >> 16: case SIL_FAULT:
err |= __get_user(tmp, &from->si_addr); err |= __get_user(tmp, &from->si_addr);
to->si_addr = (void __force __user *) to->si_addr = (void __force __user *)
(u64) (tmp & PSW32_ADDR_INSN); (u64) (tmp & PSW32_ADDR_INSN);
break; break;
case __SI_POLL >> 16: case SIL_POLL:
err |= __get_user(to->si_band, &from->si_band); err |= __get_user(to->si_band, &from->si_band);
err |= __get_user(to->si_fd, &from->si_fd); err |= __get_user(to->si_fd, &from->si_fd);
break; break;
case __SI_TIMER >> 16: case SIL_TIMER:
err |= __get_user(to->si_tid, &from->si_tid); err |= __get_user(to->si_tid, &from->si_tid);
err |= __get_user(to->si_overrun, &from->si_overrun); err |= __get_user(to->si_overrun, &from->si_overrun);
err |= __get_user(to->si_int, &from->si_int); err |= __get_user(to->si_int, &from->si_int);
......
...@@ -16,10 +16,17 @@ ...@@ -16,10 +16,17 @@
#define SI_NOINFO 32767 /* no information in siginfo_t */ #define SI_NOINFO 32767 /* no information in siginfo_t */
/*
* SIGFPE si_codes
*/
#ifdef __KERNEL__
#define FPE_FIXME 0 /* Broken dup of SI_USER */
#endif /* __KERNEL__ */
/* /*
* SIGEMT si_codes * SIGEMT si_codes
*/ */
#define EMT_TAGOVF (__SI_FAULT|1) /* tag overflow */ #define EMT_TAGOVF 1 /* tag overflow */
#define NSIGEMT 1 #define NSIGEMT 1
#endif /* _UAPI__SPARC_SIGINFO_H */ #endif /* _UAPI__SPARC_SIGINFO_H */
...@@ -85,34 +85,34 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from) ...@@ -85,34 +85,34 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
at the same time. */ at the same time. */
err = __put_user(from->si_signo, &to->si_signo); err = __put_user(from->si_signo, &to->si_signo);
err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user(from->si_errno, &to->si_errno);
err |= __put_user((short)from->si_code, &to->si_code); err |= __put_user(from->si_code, &to->si_code);
if (from->si_code < 0) if (from->si_code < 0)
err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
else { else {
switch (from->si_code >> 16) { switch (siginfo_layout(from->si_signo, from->si_code)) {
case __SI_TIMER >> 16: case SIL_TIMER:
err |= __put_user(from->si_tid, &to->si_tid); err |= __put_user(from->si_tid, &to->si_tid);
err |= __put_user(from->si_overrun, &to->si_overrun); err |= __put_user(from->si_overrun, &to->si_overrun);
err |= __put_user(from->si_int, &to->si_int); err |= __put_user(from->si_int, &to->si_int);
break; break;
case __SI_CHLD >> 16: case SIL_CHLD:
err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_stime, &to->si_stime);
err |= __put_user(from->si_status, &to->si_status); err |= __put_user(from->si_status, &to->si_status);
default: default:
case SIL_KILL:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
break; break;
case __SI_FAULT >> 16: case SIL_FAULT:
err |= __put_user(from->si_trapno, &to->si_trapno); err |= __put_user(from->si_trapno, &to->si_trapno);
err |= __put_user((unsigned long)from->si_addr, &to->si_addr); err |= __put_user((unsigned long)from->si_addr, &to->si_addr);
break; break;
case __SI_POLL >> 16: case SIL_POLL:
err |= __put_user(from->si_band, &to->si_band); err |= __put_user(from->si_band, &to->si_band);
err |= __put_user(from->si_fd, &to->si_fd); err |= __put_user(from->si_fd, &to->si_fd);
break; break;
case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ case SIL_RT:
case __SI_MESGQ >> 16:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_int, &to->si_int); err |= __put_user(from->si_int, &to->si_int);
......
...@@ -306,7 +306,7 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc, ...@@ -306,7 +306,7 @@ void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
info.si_errno = 0; info.si_errno = 0;
info.si_addr = (void __user *)pc; info.si_addr = (void __user *)pc;
info.si_trapno = 0; info.si_trapno = 0;
info.si_code = __SI_FAULT; info.si_code = FPE_FIXME;
if ((fsr & 0x1c000) == (1 << 14)) { if ((fsr & 0x1c000) == (1 << 14)) {
if (fsr & 0x10) if (fsr & 0x10)
info.si_code = FPE_FLTINV; info.si_code = FPE_FLTINV;
......
...@@ -2303,7 +2303,7 @@ static void do_fpe_common(struct pt_regs *regs) ...@@ -2303,7 +2303,7 @@ static void do_fpe_common(struct pt_regs *regs)
info.si_errno = 0; info.si_errno = 0;
info.si_addr = (void __user *)regs->tpc; info.si_addr = (void __user *)regs->tpc;
info.si_trapno = 0; info.si_trapno = 0;
info.si_code = __SI_FAULT; info.si_code = FPE_FIXME;
if ((fsr & 0x1c000) == (1 << 14)) { if ((fsr & 0x1c000) == (1 << 14)) {
if (fsr & 0x10) if (fsr & 0x10)
info.si_code = FPE_FLTINV; info.si_code = FPE_FLTINV;
......
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
/* /*
* Additional Tile-specific SIGILL si_codes * Additional Tile-specific SIGILL si_codes
*/ */
#define ILL_DBLFLT (__SI_FAULT|9) /* double fault */ #define ILL_DBLFLT 9 /* double fault */
#define ILL_HARDWALL (__SI_FAULT|10) /* user networks hardwall violation */ #define ILL_HARDWALL 10 /* user networks hardwall violation */
#undef NSIGILL #undef NSIGILL
#define NSIGILL 10 #define NSIGILL 10
......
...@@ -64,7 +64,7 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr ...@@ -64,7 +64,7 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr
3 ints plus the relevant union member. */ 3 ints plus the relevant union member. */
err = __put_user(from->si_signo, &to->si_signo); err = __put_user(from->si_signo, &to->si_signo);
err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user(from->si_errno, &to->si_errno);
err |= __put_user((short)from->si_code, &to->si_code); err |= __put_user(from->si_code, &to->si_code);
if (from->si_code < 0) { if (from->si_code < 0) {
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
...@@ -77,28 +77,26 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr ...@@ -77,28 +77,26 @@ int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *fr
*/ */
err |= __put_user(from->_sifields._pad[0], err |= __put_user(from->_sifields._pad[0],
&to->_sifields._pad[0]); &to->_sifields._pad[0]);
switch (from->si_code >> 16) { switch (siginfo_layout(from->si_signo, from->si_code)) {
case __SI_FAULT >> 16: case SIL_FAULT:
break; break;
case __SI_CHLD >> 16: case SIL_CHLD:
err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_stime, &to->si_stime);
err |= __put_user(from->si_status, &to->si_status); err |= __put_user(from->si_status, &to->si_status);
/* FALL THROUGH */ /* FALL THROUGH */
default: default:
case __SI_KILL >> 16: case SIL_KILL:
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
break; break;
case __SI_POLL >> 16: case SIL_POLL:
err |= __put_user(from->si_fd, &to->si_fd); err |= __put_user(from->si_fd, &to->si_fd);
break; break;
case __SI_TIMER >> 16: case SIL_TIMER:
err |= __put_user(from->si_overrun, &to->si_overrun); err |= __put_user(from->si_overrun, &to->si_overrun);
err |= __put_user(from->si_int, &to->si_int); err |= __put_user(from->si_int, &to->si_int);
break; break;
/* This is not generated by the kernel as of now. */ case SIL_RT:
case __SI_RT >> 16:
case __SI_MESGQ >> 16:
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_int, &to->si_int); err |= __put_user(from->si_int, &to->si_int);
break; break;
......
...@@ -188,7 +188,7 @@ static int special_ill(tile_bundle_bits bundle, int *sigp, int *codep) ...@@ -188,7 +188,7 @@ static int special_ill(tile_bundle_bits bundle, int *sigp, int *codep)
/* Make it the requested signal. */ /* Make it the requested signal. */
*sigp = sig; *sigp = sig;
*codep = code | __SI_FAULT; *codep = code;
return 1; return 1;
} }
......
...@@ -129,7 +129,7 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from, ...@@ -129,7 +129,7 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
3 ints plus the relevant union member. */ 3 ints plus the relevant union member. */
put_user_ex(from->si_signo, &to->si_signo); put_user_ex(from->si_signo, &to->si_signo);
put_user_ex(from->si_errno, &to->si_errno); put_user_ex(from->si_errno, &to->si_errno);
put_user_ex((short)from->si_code, &to->si_code); put_user_ex(from->si_code, &to->si_code);
if (from->si_code < 0) { if (from->si_code < 0) {
put_user_ex(from->si_pid, &to->si_pid); put_user_ex(from->si_pid, &to->si_pid);
...@@ -142,8 +142,8 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from, ...@@ -142,8 +142,8 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
*/ */
put_user_ex(from->_sifields._pad[0], put_user_ex(from->_sifields._pad[0],
&to->_sifields._pad[0]); &to->_sifields._pad[0]);
switch (from->si_code >> 16) { switch (siginfo_layout(from->si_signo, from->si_code)) {
case __SI_FAULT >> 16: case SIL_FAULT:
if (from->si_signo == SIGBUS && if (from->si_signo == SIGBUS &&
(from->si_code == BUS_MCEERR_AR || (from->si_code == BUS_MCEERR_AR ||
from->si_code == BUS_MCEERR_AO)) from->si_code == BUS_MCEERR_AO))
...@@ -160,11 +160,11 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from, ...@@ -160,11 +160,11 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
put_user_ex(from->si_pkey, &to->si_pkey); put_user_ex(from->si_pkey, &to->si_pkey);
} }
break; break;
case __SI_SYS >> 16: case SIL_SYS:
put_user_ex(from->si_syscall, &to->si_syscall); put_user_ex(from->si_syscall, &to->si_syscall);
put_user_ex(from->si_arch, &to->si_arch); put_user_ex(from->si_arch, &to->si_arch);
break; break;
case __SI_CHLD >> 16: case SIL_CHLD:
if (!x32_ABI) { if (!x32_ABI) {
put_user_ex(from->si_utime, &to->si_utime); put_user_ex(from->si_utime, &to->si_utime);
put_user_ex(from->si_stime, &to->si_stime); put_user_ex(from->si_stime, &to->si_stime);
...@@ -174,21 +174,18 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from, ...@@ -174,21 +174,18 @@ int __copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from,
} }
put_user_ex(from->si_status, &to->si_status); put_user_ex(from->si_status, &to->si_status);
/* FALL THROUGH */ /* FALL THROUGH */
default: case SIL_KILL:
case __SI_KILL >> 16:
put_user_ex(from->si_uid, &to->si_uid); put_user_ex(from->si_uid, &to->si_uid);
break; break;
case __SI_POLL >> 16: case SIL_POLL:
put_user_ex(from->si_fd, &to->si_fd); put_user_ex(from->si_fd, &to->si_fd);
break; break;
case __SI_TIMER >> 16: case SIL_TIMER:
put_user_ex(from->si_overrun, &to->si_overrun); put_user_ex(from->si_overrun, &to->si_overrun);
put_user_ex(ptr_to_compat(from->si_ptr), put_user_ex(ptr_to_compat(from->si_ptr),
&to->si_ptr); &to->si_ptr);
break; break;
/* This is not generated by the kernel as of now. */ case SIL_RT:
case __SI_RT >> 16:
case __SI_MESGQ >> 16:
put_user_ex(from->si_uid, &to->si_uid); put_user_ex(from->si_uid, &to->si_uid);
put_user_ex(from->si_int, &to->si_int); put_user_ex(from->si_int, &to->si_int);
break; break;
......
...@@ -741,10 +741,21 @@ static void send_sigio_to_task(struct task_struct *p, ...@@ -741,10 +741,21 @@ static void send_sigio_to_task(struct task_struct *p,
si.si_signo = signum; si.si_signo = signum;
si.si_errno = 0; si.si_errno = 0;
si.si_code = reason; si.si_code = reason;
/*
* Posix definies POLL_IN and friends to be signal
* specific si_codes for SIG_POLL. Linux extended
* these si_codes to other signals in a way that is
* ambiguous if other signals also have signal
* specific si_codes. In that case use SI_SIGIO instead
* to remove the ambiguity.
*/
if (sig_specific_sicodes(signum))
si.si_code = SI_SIGIO;
/* Make sure we are called with one of the POLL_* /* Make sure we are called with one of the POLL_*
reasons, otherwise we could leak kernel stack into reasons, otherwise we could leak kernel stack into
userspace. */ userspace. */
BUG_ON((reason & __SI_MASK) != __SI_POLL); BUG_ON((reason < POLL_IN) || ((reason - POLL_IN) >= NSIGPOLL));
if (reason - POLL_IN >= NSIGPOLL) if (reason - POLL_IN >= NSIGPOLL)
si.si_band = ~0L; si.si_band = ~0L;
else else
......
...@@ -95,23 +95,23 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, ...@@ -95,23 +95,23 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
*/ */
err |= __put_user(kinfo->si_signo, &uinfo->ssi_signo); err |= __put_user(kinfo->si_signo, &uinfo->ssi_signo);
err |= __put_user(kinfo->si_errno, &uinfo->ssi_errno); err |= __put_user(kinfo->si_errno, &uinfo->ssi_errno);
err |= __put_user((short) kinfo->si_code, &uinfo->ssi_code); err |= __put_user(kinfo->si_code, &uinfo->ssi_code);
switch (kinfo->si_code & __SI_MASK) { switch (siginfo_layout(kinfo->si_signo, kinfo->si_code)) {
case __SI_KILL: case SIL_KILL:
err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid);
err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid);
break; break;
case __SI_TIMER: case SIL_TIMER:
err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid); err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid);
err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun); err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun);
err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr);
err |= __put_user(kinfo->si_int, &uinfo->ssi_int); err |= __put_user(kinfo->si_int, &uinfo->ssi_int);
break; break;
case __SI_POLL: case SIL_POLL:
err |= __put_user(kinfo->si_band, &uinfo->ssi_band); err |= __put_user(kinfo->si_band, &uinfo->ssi_band);
err |= __put_user(kinfo->si_fd, &uinfo->ssi_fd); err |= __put_user(kinfo->si_fd, &uinfo->ssi_fd);
break; break;
case __SI_FAULT: case SIL_FAULT:
err |= __put_user((long) kinfo->si_addr, &uinfo->ssi_addr); err |= __put_user((long) kinfo->si_addr, &uinfo->ssi_addr);
#ifdef __ARCH_SI_TRAPNO #ifdef __ARCH_SI_TRAPNO
err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno); err |= __put_user(kinfo->si_trapno, &uinfo->ssi_trapno);
...@@ -128,20 +128,14 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, ...@@ -128,20 +128,14 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
&uinfo->ssi_addr_lsb); &uinfo->ssi_addr_lsb);
#endif #endif
break; break;
case __SI_CHLD: case SIL_CHLD:
err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid);
err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid);
err |= __put_user(kinfo->si_status, &uinfo->ssi_status); err |= __put_user(kinfo->si_status, &uinfo->ssi_status);
err |= __put_user(kinfo->si_utime, &uinfo->ssi_utime); err |= __put_user(kinfo->si_utime, &uinfo->ssi_utime);
err |= __put_user(kinfo->si_stime, &uinfo->ssi_stime); err |= __put_user(kinfo->si_stime, &uinfo->ssi_stime);
break; break;
case __SI_RT: /* This is not generated by the kernel as of now. */ case SIL_RT:
case __SI_MESGQ: /* But this is */
err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid);
err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid);
err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr);
err |= __put_user(kinfo->si_int, &uinfo->ssi_int);
break;
default: default:
/* /*
* This case catches also the signals queued by sigqueue(). * This case catches also the signals queued by sigqueue().
......
...@@ -441,6 +441,12 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value, ...@@ -441,6 +441,12 @@ setxattr(struct dentry *d, const char __user *name, const void __user *value,
if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) || if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) ||
(strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)) (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0))
posix_acl_fix_xattr_from_user(kvalue, size); posix_acl_fix_xattr_from_user(kvalue, size);
else if (strcmp(kname, XATTR_NAME_CAPS) == 0) {
error = cap_convert_nscap(d, &kvalue, size);
if (error < 0)
goto out;
size = error;
}
} }
error = vfs_setxattr(d, kname, kvalue, size, flags); error = vfs_setxattr(d, kname, kvalue, size, flags);
......
...@@ -248,4 +248,6 @@ extern bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns); ...@@ -248,4 +248,6 @@ extern bool ptracer_capable(struct task_struct *tsk, struct user_namespace *ns);
/* audit system wants to get cap info from files as well */ /* audit system wants to get cap info from files as well */
extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
extern int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size);
#endif /* !_LINUX_CAPABILITY_H */ #endif /* !_LINUX_CAPABILITY_H */
...@@ -90,6 +90,8 @@ extern int cap_inode_setxattr(struct dentry *dentry, const char *name, ...@@ -90,6 +90,8 @@ extern int cap_inode_setxattr(struct dentry *dentry, const char *name,
extern int cap_inode_removexattr(struct dentry *dentry, const char *name); extern int cap_inode_removexattr(struct dentry *dentry, const char *name);
extern int cap_inode_need_killpriv(struct dentry *dentry); extern int cap_inode_need_killpriv(struct dentry *dentry);
extern int cap_inode_killpriv(struct dentry *dentry); extern int cap_inode_killpriv(struct dentry *dentry);
extern int cap_inode_getsecurity(struct inode *inode, const char *name,
void **buffer, bool alloc);
extern int cap_mmap_addr(unsigned long addr); extern int cap_mmap_addr(unsigned long addr);
extern int cap_mmap_file(struct file *file, unsigned long reqprot, extern int cap_mmap_file(struct file *file, unsigned long reqprot,
unsigned long prot, unsigned long flags); unsigned long prot, unsigned long flags);
......
...@@ -21,6 +21,20 @@ static inline void copy_siginfo(struct siginfo *to, struct siginfo *from) ...@@ -21,6 +21,20 @@ static inline void copy_siginfo(struct siginfo *to, struct siginfo *from)
int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from); int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from);
enum siginfo_layout {
SIL_KILL,
SIL_TIMER,
SIL_POLL,
SIL_FAULT,
SIL_CHLD,
SIL_RT,
#ifdef __ARCH_SIGSYS
SIL_SYS,
#endif
};
enum siginfo_layout siginfo_layout(int sig, int si_code);
/* /*
* Define some primitives to manipulate sigset_t. * Define some primitives to manipulate sigset_t.
*/ */
...@@ -380,10 +394,18 @@ int unhandled_signal(struct task_struct *tsk, int sig); ...@@ -380,10 +394,18 @@ int unhandled_signal(struct task_struct *tsk, int sig);
rt_sigmask(SIGCONT) | rt_sigmask(SIGCHLD) | \ rt_sigmask(SIGCONT) | rt_sigmask(SIGCHLD) | \
rt_sigmask(SIGWINCH) | rt_sigmask(SIGURG) ) rt_sigmask(SIGWINCH) | rt_sigmask(SIGURG) )
#define SIG_SPECIFIC_SICODES_MASK (\
rt_sigmask(SIGILL) | rt_sigmask(SIGFPE) | \
rt_sigmask(SIGSEGV) | rt_sigmask(SIGBUS) | \
rt_sigmask(SIGTRAP) | rt_sigmask(SIGCHLD) | \
rt_sigmask(SIGPOLL) | rt_sigmask(SIGSYS) | \
SIGEMT_MASK )
#define sig_kernel_only(sig) siginmask(sig, SIG_KERNEL_ONLY_MASK) #define sig_kernel_only(sig) siginmask(sig, SIG_KERNEL_ONLY_MASK)
#define sig_kernel_coredump(sig) siginmask(sig, SIG_KERNEL_COREDUMP_MASK) #define sig_kernel_coredump(sig) siginmask(sig, SIG_KERNEL_COREDUMP_MASK)
#define sig_kernel_ignore(sig) siginmask(sig, SIG_KERNEL_IGNORE_MASK) #define sig_kernel_ignore(sig) siginmask(sig, SIG_KERNEL_IGNORE_MASK)
#define sig_kernel_stop(sig) siginmask(sig, SIG_KERNEL_STOP_MASK) #define sig_kernel_stop(sig) siginmask(sig, SIG_KERNEL_STOP_MASK)
#define sig_specific_sicodes(sig) siginmask(sig, SIG_SPECIFIC_SICODES_MASK)
#define sig_fatal(t, signr) \ #define sig_fatal(t, signr) \
(!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \ (!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \
......
...@@ -112,8 +112,9 @@ extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t, ...@@ -112,8 +112,9 @@ extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t,
extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *); extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *);
extern int proc_setgroups_show(struct seq_file *m, void *v); extern int proc_setgroups_show(struct seq_file *m, void *v);
extern bool userns_may_setgroups(const struct user_namespace *ns); extern bool userns_may_setgroups(const struct user_namespace *ns);
extern bool in_userns(const struct user_namespace *ancestor,
const struct user_namespace *child);
extern bool current_in_userns(const struct user_namespace *target_ns); extern bool current_in_userns(const struct user_namespace *target_ns);
struct ns_common *ns_get_owner(struct ns_common *ns); struct ns_common *ns_get_owner(struct ns_common *ns);
#else #else
...@@ -144,6 +145,12 @@ static inline bool userns_may_setgroups(const struct user_namespace *ns) ...@@ -144,6 +145,12 @@ static inline bool userns_may_setgroups(const struct user_namespace *ns)
return true; return true;
} }
static inline bool in_userns(const struct user_namespace *ancestor,
const struct user_namespace *child)
{
return true;
}
static inline bool current_in_userns(const struct user_namespace *target_ns) static inline bool current_in_userns(const struct user_namespace *target_ns)
{ {
return true; return true;
......
...@@ -151,29 +151,6 @@ typedef struct siginfo { ...@@ -151,29 +151,6 @@ typedef struct siginfo {
#define si_arch _sifields._sigsys._arch #define si_arch _sifields._sigsys._arch
#endif #endif
#ifdef __KERNEL__
#define __SI_MASK 0xffff0000u
#define __SI_KILL (0 << 16)
#define __SI_TIMER (1 << 16)
#define __SI_POLL (2 << 16)
#define __SI_FAULT (3 << 16)
#define __SI_CHLD (4 << 16)
#define __SI_RT (5 << 16)
#define __SI_MESGQ (6 << 16)
#define __SI_SYS (7 << 16)
#define __SI_CODE(T,N) ((T) | ((N) & 0xffff))
#else /* __KERNEL__ */
#define __SI_KILL 0
#define __SI_TIMER 0
#define __SI_POLL 0
#define __SI_FAULT 0
#define __SI_CHLD 0
#define __SI_RT 0
#define __SI_MESGQ 0
#define __SI_SYS 0
#define __SI_CODE(T,N) (N)
#endif /* __KERNEL__ */
/* /*
* si_code values * si_code values
* Digital reserves positive values for kernel-generated signals. * Digital reserves positive values for kernel-generated signals.
...@@ -181,8 +158,8 @@ typedef struct siginfo { ...@@ -181,8 +158,8 @@ typedef struct siginfo {
#define SI_USER 0 /* sent by kill, sigsend, raise */ #define SI_USER 0 /* sent by kill, sigsend, raise */
#define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ #define SI_KERNEL 0x80 /* sent by the kernel from somewhere */
#define SI_QUEUE -1 /* sent by sigqueue */ #define SI_QUEUE -1 /* sent by sigqueue */
#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */ #define SI_TIMER -2 /* sent by timer expiration */
#define SI_MESGQ __SI_CODE(__SI_MESGQ,-3) /* sent by real time mesq state change */ #define SI_MESGQ -3 /* sent by real time mesq state change */
#define SI_ASYNCIO -4 /* sent by AIO completion */ #define SI_ASYNCIO -4 /* sent by AIO completion */
#define SI_SIGIO -5 /* sent by queued SIGIO */ #define SI_SIGIO -5 /* sent by queued SIGIO */
#define SI_TKILL -6 /* sent by tkill system call */ #define SI_TKILL -6 /* sent by tkill system call */
...@@ -194,85 +171,85 @@ typedef struct siginfo { ...@@ -194,85 +171,85 @@ typedef struct siginfo {
/* /*
* SIGILL si_codes * SIGILL si_codes
*/ */
#define ILL_ILLOPC (__SI_FAULT|1) /* illegal opcode */ #define ILL_ILLOPC 1 /* illegal opcode */
#define ILL_ILLOPN (__SI_FAULT|2) /* illegal operand */ #define ILL_ILLOPN 2 /* illegal operand */
#define ILL_ILLADR (__SI_FAULT|3) /* illegal addressing mode */ #define ILL_ILLADR 3 /* illegal addressing mode */
#define ILL_ILLTRP (__SI_FAULT|4) /* illegal trap */ #define ILL_ILLTRP 4 /* illegal trap */
#define ILL_PRVOPC (__SI_FAULT|5) /* privileged opcode */ #define ILL_PRVOPC 5 /* privileged opcode */
#define ILL_PRVREG (__SI_FAULT|6) /* privileged register */ #define ILL_PRVREG 6 /* privileged register */
#define ILL_COPROC (__SI_FAULT|7) /* coprocessor error */ #define ILL_COPROC 7 /* coprocessor error */
#define ILL_BADSTK (__SI_FAULT|8) /* internal stack error */ #define ILL_BADSTK 8 /* internal stack error */
#define NSIGILL 8 #define NSIGILL 8
/* /*
* SIGFPE si_codes * SIGFPE si_codes
*/ */
#define FPE_INTDIV (__SI_FAULT|1) /* integer divide by zero */ #define FPE_INTDIV 1 /* integer divide by zero */
#define FPE_INTOVF (__SI_FAULT|2) /* integer overflow */ #define FPE_INTOVF 2 /* integer overflow */
#define FPE_FLTDIV (__SI_FAULT|3) /* floating point divide by zero */ #define FPE_FLTDIV 3 /* floating point divide by zero */
#define FPE_FLTOVF (__SI_FAULT|4) /* floating point overflow */ #define FPE_FLTOVF 4 /* floating point overflow */
#define FPE_FLTUND (__SI_FAULT|5) /* floating point underflow */ #define FPE_FLTUND 5 /* floating point underflow */
#define FPE_FLTRES (__SI_FAULT|6) /* floating point inexact result */ #define FPE_FLTRES 6 /* floating point inexact result */
#define FPE_FLTINV (__SI_FAULT|7) /* floating point invalid operation */ #define FPE_FLTINV 7 /* floating point invalid operation */
#define FPE_FLTSUB (__SI_FAULT|8) /* subscript out of range */ #define FPE_FLTSUB 8 /* subscript out of range */
#define NSIGFPE 8 #define NSIGFPE 8
/* /*
* SIGSEGV si_codes * SIGSEGV si_codes
*/ */
#define SEGV_MAPERR (__SI_FAULT|1) /* address not mapped to object */ #define SEGV_MAPERR 1 /* address not mapped to object */
#define SEGV_ACCERR (__SI_FAULT|2) /* invalid permissions for mapped object */ #define SEGV_ACCERR 2 /* invalid permissions for mapped object */
#define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */ #define SEGV_BNDERR 3 /* failed address bound checks */
#define SEGV_PKUERR (__SI_FAULT|4) /* failed protection key checks */ #define SEGV_PKUERR 4 /* failed protection key checks */
#define NSIGSEGV 4 #define NSIGSEGV 4
/* /*
* SIGBUS si_codes * SIGBUS si_codes
*/ */
#define BUS_ADRALN (__SI_FAULT|1) /* invalid address alignment */ #define BUS_ADRALN 1 /* invalid address alignment */
#define BUS_ADRERR (__SI_FAULT|2) /* non-existent physical address */ #define BUS_ADRERR 2 /* non-existent physical address */
#define BUS_OBJERR (__SI_FAULT|3) /* object specific hardware error */ #define BUS_OBJERR 3 /* object specific hardware error */
/* hardware memory error consumed on a machine check: action required */ /* hardware memory error consumed on a machine check: action required */
#define BUS_MCEERR_AR (__SI_FAULT|4) #define BUS_MCEERR_AR 4
/* hardware memory error detected in process but not consumed: action optional*/ /* hardware memory error detected in process but not consumed: action optional*/
#define BUS_MCEERR_AO (__SI_FAULT|5) #define BUS_MCEERR_AO 5
#define NSIGBUS 5 #define NSIGBUS 5
/* /*
* SIGTRAP si_codes * SIGTRAP si_codes
*/ */
#define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */ #define TRAP_BRKPT 1 /* process breakpoint */
#define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */ #define TRAP_TRACE 2 /* process trace trap */
#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ #define TRAP_BRANCH 3 /* process taken branch trap */
#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint/watchpoint */ #define TRAP_HWBKPT 4 /* hardware breakpoint/watchpoint */
#define NSIGTRAP 4 #define NSIGTRAP 4
/* /*
* SIGCHLD si_codes * SIGCHLD si_codes
*/ */
#define CLD_EXITED (__SI_CHLD|1) /* child has exited */ #define CLD_EXITED 1 /* child has exited */
#define CLD_KILLED (__SI_CHLD|2) /* child was killed */ #define CLD_KILLED 2 /* child was killed */
#define CLD_DUMPED (__SI_CHLD|3) /* child terminated abnormally */ #define CLD_DUMPED 3 /* child terminated abnormally */
#define CLD_TRAPPED (__SI_CHLD|4) /* traced child has trapped */ #define CLD_TRAPPED 4 /* traced child has trapped */
#define CLD_STOPPED (__SI_CHLD|5) /* child has stopped */ #define CLD_STOPPED 5 /* child has stopped */
#define CLD_CONTINUED (__SI_CHLD|6) /* stopped child has continued */ #define CLD_CONTINUED 6 /* stopped child has continued */
#define NSIGCHLD 6 #define NSIGCHLD 6
/* /*
* SIGPOLL si_codes * SIGPOLL (or any other signal without signal specific si_codes) si_codes
*/ */
#define POLL_IN (__SI_POLL|1) /* data input available */ #define POLL_IN 1 /* data input available */
#define POLL_OUT (__SI_POLL|2) /* output buffers available */ #define POLL_OUT 2 /* output buffers available */
#define POLL_MSG (__SI_POLL|3) /* input message available */ #define POLL_MSG 3 /* input message available */
#define POLL_ERR (__SI_POLL|4) /* i/o error */ #define POLL_ERR 4 /* i/o error */
#define POLL_PRI (__SI_POLL|5) /* high priority input available */ #define POLL_PRI 5 /* high priority input available */
#define POLL_HUP (__SI_POLL|6) /* device disconnected */ #define POLL_HUP 6 /* device disconnected */
#define NSIGPOLL 6 #define NSIGPOLL 6
/* /*
* SIGSYS si_codes * SIGSYS si_codes
*/ */
#define SYS_SECCOMP (__SI_SYS|1) /* seccomp triggered */ #define SYS_SECCOMP 1 /* seccomp triggered */
#define NSIGSYS 1 #define NSIGSYS 1
/* /*
......
...@@ -60,9 +60,13 @@ typedef struct __user_cap_data_struct { ...@@ -60,9 +60,13 @@ typedef struct __user_cap_data_struct {
#define VFS_CAP_U32_2 2 #define VFS_CAP_U32_2 2
#define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2)) #define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))
#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2 #define VFS_CAP_REVISION_3 0x03000000
#define VFS_CAP_U32 VFS_CAP_U32_2 #define VFS_CAP_U32_3 2
#define VFS_CAP_REVISION VFS_CAP_REVISION_2 #define XATTR_CAPS_SZ_3 (sizeof(__le32)*(2 + 2*VFS_CAP_U32_3))
#define XATTR_CAPS_SZ XATTR_CAPS_SZ_3
#define VFS_CAP_U32 VFS_CAP_U32_3
#define VFS_CAP_REVISION VFS_CAP_REVISION_3
struct vfs_cap_data { struct vfs_cap_data {
__le32 magic_etc; /* Little endian */ __le32 magic_etc; /* Little endian */
...@@ -72,6 +76,18 @@ struct vfs_cap_data { ...@@ -72,6 +76,18 @@ struct vfs_cap_data {
} data[VFS_CAP_U32]; } data[VFS_CAP_U32];
}; };
/*
* same as vfs_cap_data but with a rootid at the end
*/
struct vfs_ns_cap_data {
__le32 magic_etc;
struct {
__le32 permitted; /* Little endian */
__le32 inheritable; /* Little endian */
} data[VFS_CAP_U32];
__le32 rootid;
};
#ifndef __KERNEL__ #ifndef __KERNEL__
/* /*
......
...@@ -1615,7 +1615,7 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, ...@@ -1615,7 +1615,7 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *,
user_access_begin(); user_access_begin();
unsafe_put_user(signo, &infop->si_signo, Efault); unsafe_put_user(signo, &infop->si_signo, Efault);
unsafe_put_user(0, &infop->si_errno, Efault); unsafe_put_user(0, &infop->si_errno, Efault);
unsafe_put_user((short)info.cause, &infop->si_code, Efault); unsafe_put_user(info.cause, &infop->si_code, Efault);
unsafe_put_user(info.pid, &infop->si_pid, Efault); unsafe_put_user(info.pid, &infop->si_pid, Efault);
unsafe_put_user(info.uid, &infop->si_uid, Efault); unsafe_put_user(info.uid, &infop->si_uid, Efault);
unsafe_put_user(info.status, &infop->si_status, Efault); unsafe_put_user(info.status, &infop->si_status, Efault);
...@@ -1741,7 +1741,7 @@ COMPAT_SYSCALL_DEFINE5(waitid, ...@@ -1741,7 +1741,7 @@ COMPAT_SYSCALL_DEFINE5(waitid,
user_access_begin(); user_access_begin();
unsafe_put_user(signo, &infop->si_signo, Efault); unsafe_put_user(signo, &infop->si_signo, Efault);
unsafe_put_user(0, &infop->si_errno, Efault); unsafe_put_user(0, &infop->si_errno, Efault);
unsafe_put_user((short)info.cause, &infop->si_code, Efault); unsafe_put_user(info.cause, &infop->si_code, Efault);
unsafe_put_user(info.pid, &infop->si_pid, Efault); unsafe_put_user(info.pid, &infop->si_pid, Efault);
unsafe_put_user(info.uid, &infop->si_uid, Efault); unsafe_put_user(info.uid, &infop->si_uid, Efault);
unsafe_put_user(info.status, &infop->si_status, Efault); unsafe_put_user(info.status, &infop->si_status, Efault);
......
...@@ -101,6 +101,10 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns ...@@ -101,6 +101,10 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns
int i; int i;
int err; int err;
err = -EINVAL;
if (!in_userns(parent_pid_ns->user_ns, user_ns))
goto out;
err = -ENOSPC; err = -ENOSPC;
if (level > MAX_PID_NS_LEVEL) if (level > MAX_PID_NS_LEVEL)
goto out; goto out;
......
...@@ -728,8 +728,7 @@ static int ptrace_peek_siginfo(struct task_struct *child, ...@@ -728,8 +728,7 @@ static int ptrace_peek_siginfo(struct task_struct *child,
if (unlikely(in_compat_syscall())) { if (unlikely(in_compat_syscall())) {
compat_siginfo_t __user *uinfo = compat_ptr(data); compat_siginfo_t __user *uinfo = compat_ptr(data);
if (copy_siginfo_to_user32(uinfo, &info) || if (copy_siginfo_to_user32(uinfo, &info)) {
__put_user(info.si_code, &uinfo->si_code)) {
ret = -EFAULT; ret = -EFAULT;
break; break;
} }
...@@ -739,8 +738,7 @@ static int ptrace_peek_siginfo(struct task_struct *child, ...@@ -739,8 +738,7 @@ static int ptrace_peek_siginfo(struct task_struct *child,
{ {
siginfo_t __user *uinfo = (siginfo_t __user *) data; siginfo_t __user *uinfo = (siginfo_t __user *) data;
if (copy_siginfo_to_user(uinfo, &info) || if (copy_siginfo_to_user(uinfo, &info)) {
__put_user(info.si_code, &uinfo->si_code)) {
ret = -EFAULT; ret = -EFAULT;
break; break;
} }
......
...@@ -2686,6 +2686,51 @@ COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset, ...@@ -2686,6 +2686,51 @@ COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset,
} }
#endif #endif
enum siginfo_layout siginfo_layout(int sig, int si_code)
{
enum siginfo_layout layout = SIL_KILL;
if ((si_code > SI_USER) && (si_code < SI_KERNEL)) {
static const struct {
unsigned char limit, layout;
} filter[] = {
[SIGILL] = { NSIGILL, SIL_FAULT },
[SIGFPE] = { NSIGFPE, SIL_FAULT },
[SIGSEGV] = { NSIGSEGV, SIL_FAULT },
[SIGBUS] = { NSIGBUS, SIL_FAULT },
[SIGTRAP] = { NSIGTRAP, SIL_FAULT },
#if defined(SIGMET) && defined(NSIGEMT)
[SIGEMT] = { NSIGEMT, SIL_FAULT },
#endif
[SIGCHLD] = { NSIGCHLD, SIL_CHLD },
[SIGPOLL] = { NSIGPOLL, SIL_POLL },
#ifdef __ARCH_SIGSYS
[SIGSYS] = { NSIGSYS, SIL_SYS },
#endif
};
if ((sig < ARRAY_SIZE(filter)) && (si_code <= filter[sig].limit))
layout = filter[sig].layout;
else if (si_code <= NSIGPOLL)
layout = SIL_POLL;
} else {
if (si_code == SI_TIMER)
layout = SIL_TIMER;
else if (si_code == SI_SIGIO)
layout = SIL_POLL;
else if (si_code < 0)
layout = SIL_RT;
/* Tests to support buggy kernel ABIs */
#ifdef TRAP_FIXME
if ((sig == SIGTRAP) && (si_code == TRAP_FIXME))
layout = SIL_FAULT;
#endif
#ifdef FPE_FIXME
if ((sig == SIGFPE) && (si_code == FPE_FIXME))
layout = SIL_FAULT;
#endif
}
return layout;
}
#ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER #ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER
int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
...@@ -2708,22 +2753,20 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) ...@@ -2708,22 +2753,20 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
*/ */
err = __put_user(from->si_signo, &to->si_signo); err = __put_user(from->si_signo, &to->si_signo);
err |= __put_user(from->si_errno, &to->si_errno); err |= __put_user(from->si_errno, &to->si_errno);
err |= __put_user((short)from->si_code, &to->si_code); err |= __put_user(from->si_code, &to->si_code);
switch (from->si_code & __SI_MASK) { switch (siginfo_layout(from->si_signo, from->si_code)) {
case __SI_KILL: case SIL_KILL:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
break; break;
case __SI_TIMER: case SIL_TIMER:
err |= __put_user(from->si_tid, &to->si_tid); /* Unreached SI_TIMER is negative */
err |= __put_user(from->si_overrun, &to->si_overrun);
err |= __put_user(from->si_ptr, &to->si_ptr);
break; break;
case __SI_POLL: case SIL_POLL:
err |= __put_user(from->si_band, &to->si_band); err |= __put_user(from->si_band, &to->si_band);
err |= __put_user(from->si_fd, &to->si_fd); err |= __put_user(from->si_fd, &to->si_fd);
break; break;
case __SI_FAULT: case SIL_FAULT:
err |= __put_user(from->si_addr, &to->si_addr); err |= __put_user(from->si_addr, &to->si_addr);
#ifdef __ARCH_SI_TRAPNO #ifdef __ARCH_SI_TRAPNO
err |= __put_user(from->si_trapno, &to->si_trapno); err |= __put_user(from->si_trapno, &to->si_trapno);
...@@ -2748,30 +2791,25 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) ...@@ -2748,30 +2791,25 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
err |= __put_user(from->si_pkey, &to->si_pkey); err |= __put_user(from->si_pkey, &to->si_pkey);
#endif #endif
break; break;
case __SI_CHLD: case SIL_CHLD:
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_status, &to->si_status); err |= __put_user(from->si_status, &to->si_status);
err |= __put_user(from->si_utime, &to->si_utime); err |= __put_user(from->si_utime, &to->si_utime);
err |= __put_user(from->si_stime, &to->si_stime); err |= __put_user(from->si_stime, &to->si_stime);
break; break;
case __SI_RT: /* This is not generated by the kernel as of now. */ case SIL_RT:
case __SI_MESGQ: /* But this is */
err |= __put_user(from->si_pid, &to->si_pid); err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid); err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user(from->si_ptr, &to->si_ptr); err |= __put_user(from->si_ptr, &to->si_ptr);
break; break;
#ifdef __ARCH_SIGSYS #ifdef __ARCH_SIGSYS
case __SI_SYS: case SIL_SYS:
err |= __put_user(from->si_call_addr, &to->si_call_addr); err |= __put_user(from->si_call_addr, &to->si_call_addr);
err |= __put_user(from->si_syscall, &to->si_syscall); err |= __put_user(from->si_syscall, &to->si_syscall);
err |= __put_user(from->si_arch, &to->si_arch); err |= __put_user(from->si_arch, &to->si_arch);
break; break;
#endif #endif
default: /* this is just in case for now ... */
err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid);
break;
} }
return err; return err;
} }
......
...@@ -1896,15 +1896,11 @@ static int validate_prctl_map(struct prctl_mm_map *prctl_map) ...@@ -1896,15 +1896,11 @@ static int validate_prctl_map(struct prctl_mm_map *prctl_map)
/* /*
* Finally, make sure the caller has the rights to * Finally, make sure the caller has the rights to
* change /proc/pid/exe link: only local root should * change /proc/pid/exe link: only local sys admin should
* be allowed to. * be allowed to.
*/ */
if (prctl_map->exe_fd != (u32)-1) { if (prctl_map->exe_fd != (u32)-1) {
struct user_namespace *ns = current_user_ns(); if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN))
const struct cred *cred = current_cred();
if (!uid_eq(cred->uid, make_kuid(ns, 0)) ||
!gid_eq(cred->gid, make_kgid(ns, 0)))
goto out; goto out;
} }
......
...@@ -986,17 +986,21 @@ bool userns_may_setgroups(const struct user_namespace *ns) ...@@ -986,17 +986,21 @@ bool userns_may_setgroups(const struct user_namespace *ns)
} }
/* /*
* Returns true if @ns is the same namespace as or a descendant of * Returns true if @child is the same namespace or a descendant of
* @target_ns. * @ancestor.
*/ */
bool in_userns(const struct user_namespace *ancestor,
const struct user_namespace *child)
{
const struct user_namespace *ns;
for (ns = child; ns->level > ancestor->level; ns = ns->parent)
;
return (ns == ancestor);
}
bool current_in_userns(const struct user_namespace *target_ns) bool current_in_userns(const struct user_namespace *target_ns)
{ {
struct user_namespace *ns; return in_userns(target_ns, current_user_ns());
for (ns = current_user_ns(); ns; ns = ns->parent) {
if (ns == target_ns)
return true;
}
return false;
} }
static inline struct user_namespace *to_user_ns(struct ns_common *ns) static inline struct user_namespace *to_user_ns(struct ns_common *ns)
......
...@@ -82,8 +82,11 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, ...@@ -82,8 +82,11 @@ int cap_capable(const struct cred *cred, struct user_namespace *targ_ns,
if (ns == cred->user_ns) if (ns == cred->user_ns)
return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM;
/* Have we tried all of the parent namespaces? */ /*
if (ns == &init_user_ns) * If we're already at a lower level than we're looking for,
* we're done searching.
*/
if (ns->level <= cred->user_ns->level)
return -EPERM; return -EPERM;
/* /*
...@@ -323,6 +326,209 @@ int cap_inode_killpriv(struct dentry *dentry) ...@@ -323,6 +326,209 @@ int cap_inode_killpriv(struct dentry *dentry)
return error; return error;
} }
static bool rootid_owns_currentns(kuid_t kroot)
{
struct user_namespace *ns;
if (!uid_valid(kroot))
return false;
for (ns = current_user_ns(); ; ns = ns->parent) {
if (from_kuid(ns, kroot) == 0)
return true;
if (ns == &init_user_ns)
break;
}
return false;
}
static __u32 sansflags(__u32 m)
{
return m & ~VFS_CAP_FLAGS_EFFECTIVE;
}
static bool is_v2header(size_t size, __le32 magic)
{
__u32 m = le32_to_cpu(magic);
if (size != XATTR_CAPS_SZ_2)
return false;
return sansflags(m) == VFS_CAP_REVISION_2;
}
static bool is_v3header(size_t size, __le32 magic)
{
__u32 m = le32_to_cpu(magic);
if (size != XATTR_CAPS_SZ_3)
return false;
return sansflags(m) == VFS_CAP_REVISION_3;
}
/*
* getsecurity: We are called for security.* before any attempt to read the
* xattr from the inode itself.
*
* This gives us a chance to read the on-disk value and convert it. If we
* return -EOPNOTSUPP, then vfs_getxattr() will call the i_op handler.
*
* Note we are not called by vfs_getxattr_alloc(), but that is only called
* by the integrity subsystem, which really wants the unconverted values -
* so that's good.
*/
int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer,
bool alloc)
{
int size, ret;
kuid_t kroot;
uid_t root, mappedroot;
char *tmpbuf = NULL;
struct vfs_cap_data *cap;
struct vfs_ns_cap_data *nscap;
struct dentry *dentry;
struct user_namespace *fs_ns;
if (strcmp(name, "capability") != 0)
return -EOPNOTSUPP;
dentry = d_find_alias(inode);
if (!dentry)
return -EINVAL;
size = sizeof(struct vfs_ns_cap_data);
ret = (int) vfs_getxattr_alloc(dentry, XATTR_NAME_CAPS,
&tmpbuf, size, GFP_NOFS);
dput(dentry);
if (ret < 0)
return ret;
fs_ns = inode->i_sb->s_user_ns;
cap = (struct vfs_cap_data *) tmpbuf;
if (is_v2header((size_t) ret, cap->magic_etc)) {
/* If this is sizeof(vfs_cap_data) then we're ok with the
* on-disk value, so return that. */
if (alloc)
*buffer = tmpbuf;
else
kfree(tmpbuf);
return ret;
} else if (!is_v3header((size_t) ret, cap->magic_etc)) {
kfree(tmpbuf);
return -EINVAL;
}
nscap = (struct vfs_ns_cap_data *) tmpbuf;
root = le32_to_cpu(nscap->rootid);
kroot = make_kuid(fs_ns, root);
/* If the root kuid maps to a valid uid in current ns, then return
* this as a nscap. */
mappedroot = from_kuid(current_user_ns(), kroot);
if (mappedroot != (uid_t)-1 && mappedroot != (uid_t)0) {
if (alloc) {
*buffer = tmpbuf;
nscap->rootid = cpu_to_le32(mappedroot);
} else
kfree(tmpbuf);
return size;
}
if (!rootid_owns_currentns(kroot)) {
kfree(tmpbuf);
return -EOPNOTSUPP;
}
/* This comes from a parent namespace. Return as a v2 capability */
size = sizeof(struct vfs_cap_data);
if (alloc) {
*buffer = kmalloc(size, GFP_ATOMIC);
if (*buffer) {
struct vfs_cap_data *cap = *buffer;
__le32 nsmagic, magic;
magic = VFS_CAP_REVISION_2;
nsmagic = le32_to_cpu(nscap->magic_etc);
if (nsmagic & VFS_CAP_FLAGS_EFFECTIVE)
magic |= VFS_CAP_FLAGS_EFFECTIVE;
memcpy(&cap->data, &nscap->data, sizeof(__le32) * 2 * VFS_CAP_U32);
cap->magic_etc = cpu_to_le32(magic);
}
}
kfree(tmpbuf);
return size;
}
static kuid_t rootid_from_xattr(const void *value, size_t size,
struct user_namespace *task_ns)
{
const struct vfs_ns_cap_data *nscap = value;
uid_t rootid = 0;
if (size == XATTR_CAPS_SZ_3)
rootid = le32_to_cpu(nscap->rootid);
return make_kuid(task_ns, rootid);
}
static bool validheader(size_t size, __le32 magic)
{
return is_v2header(size, magic) || is_v3header(size, magic);
}
/*
* User requested a write of security.capability. If needed, update the
* xattr to change from v2 to v3, or to fixup the v3 rootid.
*
* If all is ok, we return the new size, on error return < 0.
*/
int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size)
{
struct vfs_ns_cap_data *nscap;
uid_t nsrootid;
const struct vfs_cap_data *cap = *ivalue;
__u32 magic, nsmagic;
struct inode *inode = d_backing_inode(dentry);
struct user_namespace *task_ns = current_user_ns(),
*fs_ns = inode->i_sb->s_user_ns;
kuid_t rootid;
size_t newsize;
if (!*ivalue)
return -EINVAL;
if (!validheader(size, cap->magic_etc))
return -EINVAL;
if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP))
return -EPERM;
if (size == XATTR_CAPS_SZ_2)
if (ns_capable(inode->i_sb->s_user_ns, CAP_SETFCAP))
/* user is privileged, just write the v2 */
return size;
rootid = rootid_from_xattr(*ivalue, size, task_ns);
if (!uid_valid(rootid))
return -EINVAL;
nsrootid = from_kuid(fs_ns, rootid);
if (nsrootid == -1)
return -EINVAL;
newsize = sizeof(struct vfs_ns_cap_data);
nscap = kmalloc(newsize, GFP_ATOMIC);
if (!nscap)
return -ENOMEM;
nscap->rootid = cpu_to_le32(nsrootid);
nsmagic = VFS_CAP_REVISION_3;
magic = le32_to_cpu(cap->magic_etc);
if (magic & VFS_CAP_FLAGS_EFFECTIVE)
nsmagic |= VFS_CAP_FLAGS_EFFECTIVE;
nscap->magic_etc = cpu_to_le32(nsmagic);
memcpy(&nscap->data, &cap->data, sizeof(__le32) * 2 * VFS_CAP_U32);
kvfree(*ivalue);
*ivalue = nscap;
return newsize;
}
/* /*
* Calculate the new process capability sets from the capability sets attached * Calculate the new process capability sets from the capability sets attached
* to a file. * to a file.
...@@ -376,7 +582,10 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data ...@@ -376,7 +582,10 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
__u32 magic_etc; __u32 magic_etc;
unsigned tocopy, i; unsigned tocopy, i;
int size; int size;
struct vfs_cap_data caps; struct vfs_ns_cap_data data, *nscaps = &data;
struct vfs_cap_data *caps = (struct vfs_cap_data *) &data;
kuid_t rootkuid;
struct user_namespace *fs_ns = inode->i_sb->s_user_ns;
memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data)); memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
...@@ -384,18 +593,20 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data ...@@ -384,18 +593,20 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
return -ENODATA; return -ENODATA;
size = __vfs_getxattr((struct dentry *)dentry, inode, size = __vfs_getxattr((struct dentry *)dentry, inode,
XATTR_NAME_CAPS, &caps, XATTR_CAPS_SZ); XATTR_NAME_CAPS, &data, XATTR_CAPS_SZ);
if (size == -ENODATA || size == -EOPNOTSUPP) if (size == -ENODATA || size == -EOPNOTSUPP)
/* no data, that's ok */ /* no data, that's ok */
return -ENODATA; return -ENODATA;
if (size < 0) if (size < 0)
return size; return size;
if (size < sizeof(magic_etc)) if (size < sizeof(magic_etc))
return -EINVAL; return -EINVAL;
cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc); cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps->magic_etc);
rootkuid = make_kuid(fs_ns, 0);
switch (magic_etc & VFS_CAP_REVISION_MASK) { switch (magic_etc & VFS_CAP_REVISION_MASK) {
case VFS_CAP_REVISION_1: case VFS_CAP_REVISION_1:
if (size != XATTR_CAPS_SZ_1) if (size != XATTR_CAPS_SZ_1)
...@@ -407,15 +618,27 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data ...@@ -407,15 +618,27 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
return -EINVAL; return -EINVAL;
tocopy = VFS_CAP_U32_2; tocopy = VFS_CAP_U32_2;
break; break;
case VFS_CAP_REVISION_3:
if (size != XATTR_CAPS_SZ_3)
return -EINVAL;
tocopy = VFS_CAP_U32_3;
rootkuid = make_kuid(fs_ns, le32_to_cpu(nscaps->rootid));
break;
default: default:
return -EINVAL; return -EINVAL;
} }
/* Limit the caps to the mounter of the filesystem
* or the more limited uid specified in the xattr.
*/
if (!rootid_owns_currentns(rootkuid))
return -ENODATA;
CAP_FOR_EACH_U32(i) { CAP_FOR_EACH_U32(i) {
if (i >= tocopy) if (i >= tocopy)
break; break;
cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted); cpu_caps->permitted.cap[i] = le32_to_cpu(caps->data[i].permitted);
cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable); cpu_caps->inheritable.cap[i] = le32_to_cpu(caps->data[i].inheritable);
} }
cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK;
...@@ -453,8 +676,8 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c ...@@ -453,8 +676,8 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c
rc = get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps); rc = get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps);
if (rc < 0) { if (rc < 0) {
if (rc == -EINVAL) if (rc == -EINVAL)
printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n", printk(KERN_NOTICE "Invalid argument reading file caps for %s\n",
__func__, rc, bprm->filename); bprm->filename);
else if (rc == -ENODATA) else if (rc == -ENODATA)
rc = 0; rc = 0;
goto out; goto out;
...@@ -633,15 +856,19 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) ...@@ -633,15 +856,19 @@ int cap_bprm_set_creds(struct linux_binprm *bprm)
int cap_inode_setxattr(struct dentry *dentry, const char *name, int cap_inode_setxattr(struct dentry *dentry, const char *name,
const void *value, size_t size, int flags) const void *value, size_t size, int flags)
{ {
if (!strcmp(name, XATTR_NAME_CAPS)) { /* Ignore non-security xattrs */
if (!capable(CAP_SETFCAP)) if (strncmp(name, XATTR_SECURITY_PREFIX,
return -EPERM; sizeof(XATTR_SECURITY_PREFIX) - 1) != 0)
return 0;
/*
* For XATTR_NAME_CAPS the check will be done in
* cap_convert_nscap(), called by setxattr()
*/
if (strcmp(name, XATTR_NAME_CAPS) == 0)
return 0; return 0;
}
if (!strncmp(name, XATTR_SECURITY_PREFIX, if (!capable(CAP_SYS_ADMIN))
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
return 0; return 0;
} }
...@@ -659,15 +886,22 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name, ...@@ -659,15 +886,22 @@ int cap_inode_setxattr(struct dentry *dentry, const char *name,
*/ */
int cap_inode_removexattr(struct dentry *dentry, const char *name) int cap_inode_removexattr(struct dentry *dentry, const char *name)
{ {
if (!strcmp(name, XATTR_NAME_CAPS)) { /* Ignore non-security xattrs */
if (!capable(CAP_SETFCAP)) if (strncmp(name, XATTR_SECURITY_PREFIX,
sizeof(XATTR_SECURITY_PREFIX) - 1) != 0)
return 0;
if (strcmp(name, XATTR_NAME_CAPS) == 0) {
/* security.capability gets namespaced */
struct inode *inode = d_backing_inode(dentry);
if (!inode)
return -EINVAL;
if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP))
return -EPERM; return -EPERM;
return 0; return 0;
} }
if (!strncmp(name, XATTR_SECURITY_PREFIX, if (!capable(CAP_SYS_ADMIN))
sizeof(XATTR_SECURITY_PREFIX) - 1) &&
!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
return 0; return 0;
} }
...@@ -1054,6 +1288,7 @@ struct security_hook_list capability_hooks[] __lsm_ro_after_init = { ...@@ -1054,6 +1288,7 @@ struct security_hook_list capability_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds), LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds),
LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv), LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv),
LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv), LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv),
LSM_HOOK_INIT(inode_getsecurity, cap_inode_getsecurity),
LSM_HOOK_INIT(mmap_addr, cap_mmap_addr), LSM_HOOK_INIT(mmap_addr, cap_mmap_addr),
LSM_HOOK_INIT(mmap_file, cap_mmap_file), LSM_HOOK_INIT(mmap_file, cap_mmap_file),
LSM_HOOK_INIT(task_fix_setuid, cap_task_fix_setuid), LSM_HOOK_INIT(task_fix_setuid, cap_task_fix_setuid),
......
...@@ -391,8 +391,7 @@ void handler(int signum, siginfo_t *si, void *vucontext) ...@@ -391,8 +391,7 @@ void handler(int signum, siginfo_t *si, void *vucontext)
br_count++; br_count++;
dprintf1("#BR 0x%jx (total seen: %d)\n", status, br_count); dprintf1("#BR 0x%jx (total seen: %d)\n", status, br_count);
#define __SI_FAULT (3 << 16) #define SEGV_BNDERR 3 /* failed address bound checks */
#define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */
dprintf2("Saw a #BR! status 0x%jx at %016lx br_reason: %jx\n", dprintf2("Saw a #BR! status 0x%jx at %016lx br_reason: %jx\n",
status, ip, br_reason); status, ip, br_reason);
......
...@@ -212,19 +212,18 @@ void dump_mem(void *dumpme, int len_bytes) ...@@ -212,19 +212,18 @@ void dump_mem(void *dumpme, int len_bytes)
} }
} }
#define __SI_FAULT (3 << 16) #define SEGV_BNDERR 3 /* failed address bound checks */
#define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */ #define SEGV_PKUERR 4
#define SEGV_PKUERR (__SI_FAULT|4)
static char *si_code_str(int si_code) static char *si_code_str(int si_code)
{ {
if (si_code & SEGV_MAPERR) if (si_code == SEGV_MAPERR)
return "SEGV_MAPERR"; return "SEGV_MAPERR";
if (si_code & SEGV_ACCERR) if (si_code == SEGV_ACCERR)
return "SEGV_ACCERR"; return "SEGV_ACCERR";
if (si_code & SEGV_BNDERR) if (si_code == SEGV_BNDERR)
return "SEGV_BNDERR"; return "SEGV_BNDERR";
if (si_code & SEGV_PKUERR) if (si_code == SEGV_PKUERR)
return "SEGV_PKUERR"; return "SEGV_PKUERR";
return "UNKNOWN"; return "UNKNOWN";
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment