Exemple #1
0
asmlinkage long
efab_linux_trampoline_sigaction(int sig, const struct sigaction *act,
                                struct sigaction *oact, size_t sigsetsize)
{
  int rc = 0;
  struct sigaction old, new;
  struct mm_signal_data *tramp_data;
  int pass_to_kernel = 0;

  efab_syscall_enter();

  if( sigsetsize != sizeof(sigset_t) ) {
    efab_syscall_exit();
    return -EINVAL;
  }

  /* Is it our process? */
  if( efab_signal_get_tramp_data(&tramp_data) ) {
    rc = efab_linux_sys_sigaction(sig, act, oact);
    efab_syscall_exit();
    return rc;
  }

  if( act != NULL ) {
    /* If we are in vfork child, we have the same mm but different sighand.
     * We should not change parent UL structure in this case, se we'd
     * better off from this signal while running in the child. */
    if( tramp_data->kernel_sighand != current->sighand )
      pass_to_kernel = 1;
    else {
      rc = copy_from_user(&new, act, sizeof(new));
      if( rc != 0 ) {
        efab_signal_put_tramp_data(tramp_data);
        efab_syscall_exit();
        return -EFAULT;
      }
    }
  }

  rc = efab_signal_do_sigaction(sig,
                                (act && !pass_to_kernel) ? &new : NULL,
                                oact ? &old : NULL, tramp_data,
                                &pass_to_kernel);
  efab_signal_put_tramp_data(tramp_data);

  if( pass_to_kernel )
    efab_linux_sys_sigaction(sig, act, NULL);

  if( rc == 0 && oact != NULL ) {
    rc = copy_to_user(oact, &old, sizeof(old));
    if( rc != 0 ) {
      efab_syscall_exit();
      return -EFAULT;
    }
  }
  efab_syscall_exit();
  return rc;
}
/* Our close handler, 64-bit */
static int efab_linux_trampoline_close64(int fd)
{
  /* Firstly, is this one our sockets?  If not, do the usual thing */
  struct file *f;
  int rc;

  TRAMP_DEBUG("close64: %d\n", fd);

  efab_syscall_enter();

  f = fget (fd);
  if (f) {
      if (FILE_IS_ENDPOINT(f)) {
        /* Yep -- it's one of ours.  This means current process must be using the
         * module (otherwise how did one of our sockets get in this proc's fd
         * table?).  It seems it didn't get intercepted -- trampoline back up.
         * However, only set up trampoline if this has been called via the
         * correct sys-call entry point
         */
        if (setup_trampoline (PT_REGS_FROM_SYSCALL(), 
                              CI_TRAMP_OPCODE_CLOSE, fd, TRAMPOLINE_BITS_64) == 0)
        {
            /* The trampoline will get run.  Let it handle the rest. */
            fput(f);
            efab_syscall_exit();
            return 0;
        }
    }
    /* Undo the fget above */
    fput(f);
  }

  TRAMP_DEBUG("going unto %p\n", THUNKPTR(state.replace_close->original_entry64));
  /* Not one of our FDs -- usual close */
  rc = ((int (*)(int))THUNKPTR(state.replace_close->original_entry64))(fd);
  TRAMP_DEBUG("Close64: Chain returns %d \n", rc);
  efab_syscall_exit();
  return rc;
}
Exemple #3
0
/* On PPC there is no 32-bit sigaction - or rather, all sigaction calls are 32-bit.
 */
asmlinkage int
efab_linux_trampoline_sigaction32(int sig, const struct sigaction32 *act32,
                                  struct sigaction32 *oact32,
                                  unsigned int sigsetsize)
{
  struct sigaction act, oact;
  compat_sigset_t set32;
  int rc;
  struct mm_signal_data *tramp_data;
  int pass_to_kernel = 0;

  efab_syscall_enter();

  if( sigsetsize != sizeof(compat_sigset_t) ) {
    efab_syscall_exit();
    return -EINVAL;
  }

  /* Is it our process? */
  if( efab_signal_get_tramp_data(&tramp_data) ) {
    rc = efab_linux_sys_sigaction32(sig, act32, oact32);
    efab_syscall_exit();
    return rc;
  }

  /* Do not change UL data if we are in vfork child */
  if( act32 != NULL && tramp_data->kernel_sighand != current->sighand )
    pass_to_kernel = 1;

  if( act32 != NULL && !pass_to_kernel ) {
    compat_uptr_t handler, restorer;

    if( !access_ok(VERIFY_READ, act32, sizeof(*act32)) ||
        __get_user(handler, &act32->sa_handler) ||
        __get_user(act.sa_flags, &act32->sa_flags) ||
        __get_user(restorer, &act32->sa_restorer) ||
        __copy_from_user(&set32, &act32->sa_mask, sizeof(compat_sigset_t)) ) {
      efab_signal_put_tramp_data(tramp_data);
      efab_syscall_exit();
      return -EFAULT;
    }
    act.sa_handler = compat_ptr(handler);
    act.sa_restorer = compat_ptr(restorer);

    ci_assert_ge(_COMPAT_NSIG_WORDS, _NSIG_WORDS << 1);
    switch (_NSIG_WORDS) { /* Note: no break */
    case 4: act.sa_mask.sig[3] = set32.sig[6] | (((long)set32.sig[7]) << 32);
    case 3: act.sa_mask.sig[2] = set32.sig[4] | (((long)set32.sig[5]) << 32);
    case 2: act.sa_mask.sig[1] = set32.sig[2] | (((long)set32.sig[3]) << 32);
    case 1: act.sa_mask.sig[0] = set32.sig[0] | (((long)set32.sig[1]) << 32);
    }
  }

  rc = efab_signal_do_sigaction(sig,
                                (act32 && !pass_to_kernel) ? &act : NULL,
                                oact32 ? &oact : NULL, tramp_data,
                                &pass_to_kernel);
  efab_signal_put_tramp_data(tramp_data);
  if( pass_to_kernel )
    efab_linux_sys_sigaction32(sig, act32, NULL);

  if( rc == 0 && oact32 != NULL ) {
    switch (_NSIG_WORDS) { /* Note: no break */
    case 4:
      set32.sig[7] = (oact.sa_mask.sig[3] >> 32);
      set32.sig[6] = oact.sa_mask.sig[3];
    case 3:
      set32.sig[5] = (oact.sa_mask.sig[2] >> 32);
      set32.sig[4] = oact.sa_mask.sig[2];
    case 2:
      set32.sig[3] = (oact.sa_mask.sig[1] >> 32);
      set32.sig[2] = oact.sa_mask.sig[1];
    case 1:
      set32.sig[1] = (oact.sa_mask.sig[0] >> 32);
      set32.sig[0] = oact.sa_mask.sig[0];
    }

    if( !access_ok(VERIFY_WRITE, oact32, sizeof(*oact32)) ||
        __put_user(ptr_to_compat(oact.sa_handler), &oact32->sa_handler) ||
        __put_user(ptr_to_compat(oact.sa_restorer), &oact32->sa_restorer) ||
        __put_user(oact.sa_flags, &oact32->sa_flags) ||
        __copy_to_user(&oact32->sa_mask, &set32, sizeof(compat_sigset_t))) {
      efab_syscall_exit();
      return -EFAULT;
    }
  }

  efab_syscall_exit();
  return rc;
}