예제 #1
0
jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd) {
    JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
    static jmethodID ctor = e->GetMethodID(JniConstants::fileDescriptorClass, "<init>", "()V");
    jobject fileDescriptor = (*env)->NewObject(e, JniConstants::fileDescriptorClass, ctor);
    jniSetFileDescriptorOfFD(env, fileDescriptor, fd);
    return fileDescriptor;
}
/*
 * Creates a socket suitable for raw socket operations.  The socket is
 * bound to the interface specified by the supplied name.  The socket
 * value is placed into the supplied FileDescriptor instance.
 *
 * TODO(chesnutt): consider breaking this into pieces: create a
 * variety of constructors for different socket types, then a generic
 * setBlocking() method followed by polymorphic bind().
 */
static void RawSocket_create(JNIEnv* env, jclass, jobject fileDescriptor,
    jshort protocolType, jstring interfaceName)
{

  ScopedUtfChars ifname(env, interfaceName);
  if (ifname.c_str() == NULL) {
    return;
  }

  memset(&su, 0, sizeof(su));
  su.sll.sll_family = PF_PACKET;
  su.sll.sll_protocol = htons(protocolType);
  su.sll.sll_ifindex = if_nametoindex(ifname.c_str());
  int sock = socket(PF_PACKET, SOCK_DGRAM, htons(protocolType));

  if (sock == -1) {
    ALOGE("Can't create socket %s", strerror(errno));
    jniThrowSocketException(env, errno);
    return;
  }

  jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
  if (!setBlocking(sock, false)) {
    ALOGE("Can't set non-blocking mode on socket %s", strerror(errno));
    jniThrowSocketException(env, errno);
    return;
  }

  int err = bind(sock, &su.sa, sizeof(su));
  if (err != 0) {
    ALOGE("Socket bind error %s", strerror(errno));
    jniThrowSocketException(env, errno);
    return;
  }
}
예제 #3
0
static void OSNetworkSystem_socket(JNIEnv* env, jobject, jobject fileDescriptor, jboolean stream) {
    if (fileDescriptor == NULL) {
        jniThrowNullPointerException(env, NULL);
        errno = EBADF;
        return;
    }

    // Try IPv6 but fall back to IPv4...
    int type = stream ? SOCK_STREAM : SOCK_DGRAM;
    int fd = socket(AF_INET6, type, 0);
    if (fd == -1 && errno == EAFNOSUPPORT) {
        fd = socket(AF_INET, type, 0);
    }
    if (fd == -1) {
        jniThrowSocketException(env, errno);
        return;
    } else {
        jniSetFileDescriptorOfFD(env, fileDescriptor, fd);
    }

#ifdef __linux__
    // The RFC (http://www.ietf.org/rfc/rfc3493.txt) says that IPV6_MULTICAST_HOPS defaults to 1.
    // The Linux kernel (at least up to 2.6.32) accidentally defaults to 64 (which would be correct
    // for the *unicast* hop limit). See http://www.spinics.net/lists/netdev/msg129022.html.
    // When that bug is fixed, we can remove this code. Until then, we manually set the hop
    // limit on IPv6 datagram sockets. (IPv4 is already correct.)
    if (type == SOCK_DGRAM && getSocketAddressFamily(fd) == AF_INET6) {
        int ttl = 1;
        setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(int));
    }
#endif
}
static void android_os_MemoryFile_close(JNIEnv* env, jobject clazz, jobject fileDescriptor)
{
    int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
    if (fd >= 0) {
        jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
        close(fd);
    }
}
예제 #5
0
jobject jniCreateFileDescriptor(C_JNIEnv* env, int fd) {
	JNIEnv* e = reinterpret_cast<JNIEnv*>(env);
	tryInitCachedFields(e);

	jobject fileDescriptor = (*env)->NewObject(e,
			gCachedFields.fileDescriptorClass,
			gCachedFields.fileDescriptorCtor);
	jniSetFileDescriptorOfFD(env, fileDescriptor, fd);
	return fileDescriptor;
}
static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jclass clazz, jobject object)
{
    if (object == NULL) {
        jniThrowNullPointerException(env, NULL);
        return;
    }
    int fd = jniGetFDFromFileDescriptor(env, object);
    if (fd >= 0) {
        jniSetFileDescriptorOfFD(env, object, -1);
    }
}
예제 #7
0
static void OSNetworkSystem_close(JNIEnv* env, jobject, jobject fileDescriptor) {
    NetFd fd(env, fileDescriptor);
    if (fd.isClosed()) {
        return;
    }

    int oldFd = fd.get();
    jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
    AsynchronousSocketCloseMonitor::signalBlockedThreads(oldFd);
    close(oldFd);
}
static void android_security_cts_NetlinkSocket_create(JNIEnv* env, jclass,
    jobject fileDescriptor)
{
    int sock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
    if (sock == -1) {
        ALOGE("Can't create socket %s", strerror(errno));
        jclass SocketException = env->FindClass("java/net/SocketException");
        env->ThrowNew(SocketException, "Can't create socket");
        return;
    }
    jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
}
/*
 * Class:     info_kghost_android_openvpn_ManagementSocket
 * Method:    read
 * Signature: (ILjava/nio/ByteBuffer;IILinfo/kghost/android/openvpn/FileDescriptorHolder;)I
 */
JNIEXPORT jint JNICALL Java_info_kghost_android_openvpn_ManagementSocket_read__ILjava_nio_ByteBuffer_2IILinfo_kghost_android_openvpn_FileDescriptorHolder_2
  (JNIEnv *env, jclass cls, jint socket, jobject buffer, jint offset, jint length, jobject fd)
{
  if (socket < 0) {
    throwError(env, "java/lang/IllegalArgumentException", "socket");
    return -1;
  }

  jlong cap = (*env)->GetDirectBufferCapacity(env, buffer);
  char* ptr = (*env)->GetDirectBufferAddress(env, buffer);
  int recvfd = -1;

  if (cap-offset < length) {
    throwError(env, "java/lang/IllegalArgumentException", "socket");
    return -1;
  }
  int result = read_fd(socket, ptr+offset, length, &recvfd);
  if (result < 0) {
    switch (errno) {
      case EBADF:
      case ENOTSOCK:
      case ENOTCONN:
      case ECONNREFUSED:
        throwError(env, "java/lang/IllegalArgumentException", "socket");
        break;
      case EINVAL:
        throwError(env, "java/lang/IllegalArgumentException", "inval");
        break;
      case EFAULT:
        throwError(env, "java/lang/IllegalArgumentException", "buffer");
        break;
      case EINTR:
        throwError(env, "java/lang/InterruptedException", "interrupted");
        break;
      case ENOMEM:
        throwError(env, "java/lang/RuntimeException", "oom");
        break;
      case EAGAIN:
        throwError(env, "java/lang/IllegalArgumentException", "non-block socket");
        break;
      default:
        throwError(env, "java/lang/RuntimeException", strerror(errno));
        break;
    }
    return result;
  }

  if (recvfd >= 0) {
    jniSetFileDescriptorOfFD(env, fd, recvfd);
  }

  return result;
}
/*
 * Class:     info_kghost_android_openvpn_OpenVpn_ControlChannel
 * Method:    recv
 * Signature: (Linfo/kghost/android/openvpn/FileDescriptorHolder;Ljava/nio/Buffer;IILinfo/kghost/android/openvpn/FileDescriptorHolder;)I
 */
JNIEXPORT jint JNICALL Java_info_kghost_android_openvpn_OpenVpn_00024ControlChannel_recv
(JNIEnv *env, jclass cls, jobject socket, jobject buffer, jint offset, jint length, jobject fd) {
  int s = jniGetFDFromFileDescriptor(env, socket);
  if (s < 0) {
    throwError(env, "java/lang/IllegalArgumentException", "socket");
    return -1;
  }

  jlong cap = (*env)->GetDirectBufferCapacity(env, buffer);
  char* ptr = (*env)->GetDirectBufferAddress(env, buffer);
  int recvfd = -1;

  int result = read_fd(s, ptr+offset, min(cap-offset, length), &recvfd);
  if (result < 0) {
    switch (errno) {
      case EBADF:
      case ENOTSOCK:
      case ENOTCONN:
      case ECONNREFUSED:
        throwError(env, "java/lang/IllegalArgumentException", "socket");
        break;
      case EINVAL:
        throwError(env, "java/lang/IllegalArgumentException", "inval");
        break;
      case EFAULT:
        throwError(env, "java/lang/IllegalArgumentException", "buffer");
        break;
      case EINTR:
        throwError(env, "java/lang/InterruptedException", "interrupted");
        break;
      case ENOMEM:
        throwError(env, "java/lang/RuntimeException", "oom");
        break;
      case EAGAIN:
        throwError(env, "java/lang/IllegalArgumentException", "non-block socket");
        break;
      default:
        throwError(env, "java/lang/RuntimeException", "unknown error");
        break;
    }
    return result;
  }

  if (recvfd >= 0) {
    jniSetFileDescriptorOfFD(env, fd, recvfd);
  }

  return result;
}
/** Executes a command in a child process. */
static pid_t executeProcess(JNIEnv* env, char** commands, char** environment,
        const char* workingDirectory, jobject inDescriptor,
        jobject outDescriptor, jobject errDescriptor,
        jboolean redirectErrorStream) {

    // Keep track of the system properties fd so we don't close it.
    int androidSystemPropertiesFd = -1;
    char* fdString = getenv("ANDROID_PROPERTY_WORKSPACE");
    if (fdString) {
        androidSystemPropertiesFd = atoi(fdString);
    }

    // Create 4 pipes: stdin, stdout, stderr, and an exec() status pipe.
    int pipes[PIPE_COUNT * 2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
    for (int i = 0; i < PIPE_COUNT; i++) {
        if (pipe(pipes + i * 2) == -1) {
            jniThrowIOException(env, errno);
            closePipes(pipes, -1);
            return -1;
        }
    }
    int stdinIn = pipes[0];
    int stdinOut = pipes[1];
    int stdoutIn = pipes[2];
    int stdoutOut = pipes[3];
    int stderrIn = pipes[4];
    int stderrOut = pipes[5];
    int statusIn = pipes[6];
    int statusOut = pipes[7];

    pid_t childPid = fork();

    // If fork() failed...
    if (childPid == -1) {
        jniThrowIOException(env, errno);
        closePipes(pipes, -1);
        return -1;
    }

    // If this is the child process...
    if (childPid == 0) {
        /*
         * Note: We cannot malloc() or free() after this point!
         * A no-longer-running thread may be holding on to the heap lock, and
         * an attempt to malloc() or free() would result in deadlock.
         */

        // Replace stdin, out, and err with pipes.
        dup2(stdinIn, 0);
        dup2(stdoutOut, 1);
        if (redirectErrorStream) {
            dup2(stdoutOut, 2);
        } else {
            dup2(stderrOut, 2);
        }

        // Close all but statusOut. This saves some work in the next step.
        closePipes(pipes, statusOut);

        // Make statusOut automatically close if execvp() succeeds.
        fcntl(statusOut, F_SETFD, FD_CLOEXEC);

        // Close remaining unwanted open fds.
        closeNonStandardFds(statusOut, androidSystemPropertiesFd);

        // Switch to working directory.
        if (workingDirectory != NULL) {
            if (chdir(workingDirectory) == -1) {
                goto execFailed;
            }
        }

        // Set up environment.
        if (environment != NULL) {
            extern char** environ; // Standard, but not in any header file.
            environ = environment;
        }

        // Execute process. By convention, the first argument in the arg array
        // should be the command itself. In fact, I get segfaults when this
        // isn't the case.
        execvp(commands[0], commands);

        // If we got here, execvp() failed or the working dir was invalid.
        execFailed:
            int error = errno;
            write(statusOut, &error, sizeof(int));
            close(statusOut);
            exit(error);
    }

    // This is the parent process.

    // Close child's pipe ends.
    close(stdinIn);
    close(stdoutOut);
    close(stderrOut);
    close(statusOut);

    // Check status pipe for an error code. If execvp() succeeds, the other
    // end of the pipe should automatically close, in which case, we'll read
    // nothing.
    int result;
    int count = read(statusIn, &result, sizeof(int));
    close(statusIn);
    if (count > 0) {
        jniThrowIOException(env, result);

        close(stdoutIn);
        close(stdinOut);
        close(stderrIn);

        return -1;
    }

    // Fill in file descriptor wrappers.
    jniSetFileDescriptorOfFD(env, inDescriptor, stdoutIn);
    jniSetFileDescriptorOfFD(env, outDescriptor, stdinOut);
    jniSetFileDescriptorOfFD(env, errDescriptor, stderrIn);

    return childPid;
}
/** Executes a command in a child process. */
static pid_t ExecuteProcess(JNIEnv* env, char** commands, char** environment,
                            const char* workingDirectory, jobject inDescriptor,
                            jobject outDescriptor, jobject errDescriptor,
                            jboolean redirectErrorStream) {

  // Create 4 pipes: stdin, stdout, stderr, and an exec() status pipe.
  int pipes[PIPE_COUNT * 2] = { -1, -1, -1, -1, -1, -1, -1, -1 };
  for (int i = 0; i < PIPE_COUNT; i++) {
    if (pipe(pipes + i * 2) == -1) {
      jniThrowIOException(env, errno);
      ClosePipes(pipes, -1);
      return -1;
    }
  }
  int stdinIn = pipes[0];
  int stdinOut = pipes[1];
  int stdoutIn = pipes[2];
  int stdoutOut = pipes[3];
  int stderrIn = pipes[4];
  int stderrOut = pipes[5];
  int statusIn = pipes[6];
  int statusOut = pipes[7];

  pid_t childPid = fork();

  // If fork() failed...
  if (childPid == -1) {
    jniThrowIOException(env, errno);
    ClosePipes(pipes, -1);
    return -1;
  }

  // If this is the child process...
  if (childPid == 0) {
    // Note: We cannot malloc(3) or free(3) after this point!
    // A thread in the parent that no longer exists in the child may have held the heap lock
    // when we forked, so an attempt to malloc(3) or free(3) would result in deadlock.

    // Replace stdin, out, and err with pipes.
    dup2(stdinIn, 0);
    dup2(stdoutOut, 1);
    if (redirectErrorStream) {
      dup2(stdoutOut, 2);
    } else {
      dup2(stderrOut, 2);
    }

    // Close all but statusOut. This saves some work in the next step.
    ClosePipes(pipes, statusOut);

    // Make statusOut automatically close if execvp() succeeds.
    fcntl(statusOut, F_SETFD, FD_CLOEXEC);

    // Close remaining unwanted open fds.
    CloseNonStandardFds(statusOut);

    // Switch to working directory.
    if (workingDirectory != NULL) {
      if (chdir(workingDirectory) == -1) {
        AbortChild(statusOut);
      }
    }

    // Set up environment.
    if (environment != NULL) {
      extern char** environ; // Standard, but not in any header file.
      environ = environment;
    }

    // Execute process. By convention, the first argument in the arg array
    // should be the command itself.
    execvp(commands[0], commands);
    AbortChild(statusOut);
  }

  // This is the parent process.

  // Close child's pipe ends.
  close(stdinIn);
  close(stdoutOut);
  close(stderrOut);
  close(statusOut);

  // Check status pipe for an error code. If execvp(2) succeeds, the other
  // end of the pipe should automatically close, in which case, we'll read
  // nothing.
  int child_errno;
  ssize_t count = TEMP_FAILURE_RETRY(read(statusIn, &child_errno, sizeof(int)));
  close(statusIn);
  if (count > 0) {
    // chdir(2) or execvp(2) in the child failed.
    // TODO: track which so we can be more specific in the detail message.
    jniThrowIOException(env, child_errno);

    close(stdoutIn);
    close(stdinOut);
    close(stderrIn);

    // Reap our zombie child right away.
    int status;
    int rc = TEMP_FAILURE_RETRY(waitpid(childPid, &status, 0));
    if (rc == -1) {
      ALOGW("waitpid on failed exec failed: %s", strerror(errno));
    }

    return -1;
  }

  // Fill in file descriptor wrappers.
  jniSetFileDescriptorOfFD(env, inDescriptor, stdoutIn);
  jniSetFileDescriptorOfFD(env, outDescriptor, stdinOut);
  jniSetFileDescriptorOfFD(env, errDescriptor, stderrIn);

  return childPid;
}
예제 #13
0
static void OSNetworkSystem_accept(JNIEnv* env, jobject, jobject serverFileDescriptor,
        jobject newSocket, jobject clientFileDescriptor) {

    if (newSocket == NULL) {
        jniThrowNullPointerException(env, NULL);
        return;
    }

    NetFd serverFd(env, serverFileDescriptor);
    if (serverFd.isClosed()) {
        return;
    }

    sockaddr_storage ss;
    socklen_t addrLen = sizeof(ss);
    sockaddr* sa = reinterpret_cast<sockaddr*>(&ss);

    int clientFd;
    {
        int intFd = serverFd.get();
        AsynchronousSocketCloseMonitor monitor(intFd);
        clientFd = NET_FAILURE_RETRY(serverFd, accept(intFd, sa, &addrLen));
    }
    if (env->ExceptionOccurred()) {
        return;
    }
    if (clientFd == -1) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            jniThrowSocketTimeoutException(env, errno);
        } else {
            jniThrowSocketException(env, errno);
        }
        return;
    }

    // Reset the inherited read timeout to the Java-specified default of 0.
    timeval timeout(toTimeval(0));
    int rc = setsockopt(clientFd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
    if (rc == -1) {
        LOGE("couldn't reset SO_RCVTIMEO on accepted socket fd %i: %s", clientFd, strerror(errno));
        jniThrowSocketException(env, errno);
    }

    /*
     * For network sockets, put the peer address and port in instance variables.
     * We don't bother to do this for UNIX domain sockets, since most peers are
     * anonymous anyway.
     */
    if (ss.ss_family == AF_INET || ss.ss_family == AF_INET6) {
        // Remote address and port.
        jobject remoteAddress = socketAddressToInetAddress(env, &ss);
        if (remoteAddress == NULL) {
            close(clientFd);
            return;
        }
        int remotePort = getSocketAddressPort(&ss);
        env->SetObjectField(newSocket, gCachedFields.socketimpl_address, remoteAddress);
        env->SetIntField(newSocket, gCachedFields.socketimpl_port, remotePort);

        // Local port.
        memset(&ss, 0, addrLen);
        int rc = getsockname(clientFd, sa, &addrLen);
        if (rc == -1) {
            close(clientFd);
            jniThrowSocketException(env, errno);
            return;
        }
        int localPort = getSocketAddressPort(&ss);
        env->SetIntField(newSocket, gCachedFields.socketimpl_localport, localPort);
    }

    jniSetFileDescriptorOfFD(env, clientFileDescriptor, clientFd);
}
예제 #14
0
/*
 * Create a java.io.FileDescriptor given an integer fd
 */
jobject jniCreateFileDescriptor(JNIEnv* env, int fd) {
    jobject fileDescriptor = (*env)->NewObject(env,
            gCachedFields.fileDescriptorClass, gCachedFields.fileDescriptorCtor);
    jniSetFileDescriptorOfFD(env, fileDescriptor, fd);
    return fileDescriptor;
}