Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug][JNI] Parse JNI functions in native layer #4923

Open
MC-box opened this issue Sep 14, 2024 · 5 comments
Open

[Bug][JNI] Parse JNI functions in native layer #4923

MC-box opened this issue Sep 14, 2024 · 5 comments
Labels
bug Something isn't working

Comments

@MC-box
Copy link

MC-box commented Sep 14, 2024

Describe the bug
Fail to parse C code when a JNI function returns a non-JNI type

To Reproduce
The C Code:

#include <string.h>

#include "engine.h"
#include "input.h"
#include "math.h"
#include "renderer.h"
JNIEXPORT void JNICALL Java_com_termux_x11_XrActivity_init(JNIEnv *env, jobject obj) {

    // Do not allow second initialization
    if (xr_initialized) {
        return;
    }

    // Set platform flags
    memset(&xr_engine, 0, sizeof(xr_engine));
    xr_engine.PlatformFlag[PLATFORM_CONTROLLER_QUEST] = true;
    xr_engine.PlatformFlag[PLATFORM_EXTENSION_PASSTHROUGH] = true;
    xr_engine.PlatformFlag[PLATFORM_EXTENSION_PERFORMANCE] = true;

    // Get Java VM
    JavaVM* vm;
    (*env)->GetJavaVM(env, &vm);

    // Init XR
    xrJava java;
    java.vm = vm;
    java.activity = (*env)->NewGlobalRef(env, obj);
    XrEngineInit(&xr_engine, &java, "termux-x11", 1);
    XrEngineEnter(&xr_engine);
    XrInputInit(&xr_engine, &xr_input);
    XrRendererInit(&xr_engine, &xr_renderer);
    XrRendererGetResolution(&xr_engine, &xr_renderer, &xr_params[4], &xr_params[5]);
    xr_initialized = true;
    ALOGV("Init called");
}

Steps to reproduce the behavior:

  1. Run joern: ./joern
  2. joern> importCode("path/to/c","name")
  3. joern> cpg.method.name.l

Expected behavior
Joern should correctly recognize the function Java_com_termux_x11_XrActivity_init and list it in the output of cpg.method.name.l.

Output

val res3: List[String] = List("<global>", "<global>", "<operator>.assignment", "<operator>.arrayInitializer")

joern cannot recognize function: Java_com_termux_x11_XrActivity_init()

Desktop (please complete the following information):

  • Debian 5.16.18-1kali1
  • Joern Version: 4.0.67
  • Java Version: 17.0.10

Additional context
Other non-JNI type such as primitive data types will get similar results

@MC-box MC-box added the bug Something isn't working label Sep 14, 2024
@max-leuthaeuser
Copy link
Contributor

max-leuthaeuser commented Sep 14, 2024

You need to give c2cpg the path to the included files (--include <dir>) and/or you system header files location (--with-include-auto-discovery). Otherwise, definitions like JNICALL and such can not be resolved. That may lead to unparsable code.

@MC-box
Copy link
Author

MC-box commented Sep 16, 2024

But joern can resolve JNI functions whose return value is JNI type without giving c2cpg any path to the included files:

#include <string.h>

#include "engine.h"
#include "input.h"
#include "math.h"
#include "renderer.h"

JNIEXPORT jfloatArray JNICALL Java_com_termux_x11_XrActivity_getAxes(JNIEnv *env, jobject obj) {
    XrPosef lPose = XrInputGetPose(&xr_input, 0);
    XrPosef rPose = XrInputGetPose(&xr_input, 1);
    XrVector2f lThumbstick = XrInputGetJoystickState(&xr_input, 0);
    XrVector2f rThumbstick = XrInputGetJoystickState(&xr_input, 1);
    XrVector3f lPosition = xr_renderer.Projections[0].pose.position;
    XrVector3f rPosition = xr_renderer.Projections[1].pose.position;
    XrVector3f angles = xr_renderer.HmdOrientation;

    int count = 0;
    float data[32];
    data[count++] = XrQuaternionfEulerAngles(lPose.orientation).x; //L_PITCH
    data[count++] = XrQuaternionfEulerAngles(lPose.orientation).y; //L_YAW
    data[count++] = XrQuaternionfEulerAngles(lPose.orientation).z; //L_ROLL
    data[count++] = lThumbstick.x; //L_THUMBSTICK_X
    data[count++] = lThumbstick.y; //L_THUMBSTICK_Y
    data[count++] = lPose.position.x; //L_X
    data[count++] = lPose.position.y; //L_Y
    data[count++] = lPose.position.z; //L_Z
    data[count++] = XrQuaternionfEulerAngles(rPose.orientation).x; //R_PITCH
    data[count++] = XrQuaternionfEulerAngles(rPose.orientation).y; //R_YAW
    data[count++] = XrQuaternionfEulerAngles(rPose.orientation).z; //R_ROLL
    data[count++] = rThumbstick.x; //R_THUMBSTICK_X
    data[count++] = rThumbstick.y; //R_THUMBSTICK_Y
    data[count++] = rPose.position.x; //R_X
    data[count++] = rPose.position.y; //R_Y
    data[count++] = rPose.position.z; //R_Z
    data[count++] = angles.x; //HMD_PITCH
    data[count++] = angles.y; //HMD_YAW
    data[count++] = angles.z; //HMD_ROLL
    data[count++] = (lPosition.x + rPosition.x) * 0.5f; //HMD_X
    data[count++] = (lPosition.y + rPosition.y) * 0.5f; //HMD_Y
    data[count++] = (lPosition.z + rPosition.z) * 0.5f; //HMD_Z
    data[count++] = XrVector3fDistance(lPosition, rPosition); //HMD_IPD

    jfloat values[count];
    memcpy(values, data, count * sizeof(float));
    jfloatArray output = (*env)->NewFloatArray(env, count);
    (*env)->SetFloatArrayRegion(env, output, (jsize)0, (jsize)count, values);
    return output;
}

Result:

val res1: List[String] = List(
  "<global>",
  "Java_com_termux_x11_XrActivity_getAxes",
  "<global>",
  "<operator>.assignment",
  "XrInputGetPose",
  "<operator>.addressOf",
  "XrInputGetJoystickState",
  "<operator>.fieldAccess",
  "<operator>.indirectIndexAccess",
  "<operator>.alloc",
  "<operator>.postIncrement",
  "XrQuaternionfEulerAngles",
  "<operator>.multiplication",
  "<operator>.addition",
  "XrVector3fDistance",
  "memcpy",
  "<operator>.sizeOf",
  "<operator>.pointerCall",
  "<operator>.indirectFieldAccess",
  "<operator>.indirection",
  "<operator>.cast"
)

So I suppose maybe it isn't an issue with the include-path?

@max-leuthaeuser
Copy link
Contributor

max-leuthaeuser commented Sep 16, 2024

We simply use Eclipse CDT as a parser. If CDT is not able to parse it there is nothing we can do unfortunately.
You could try a c2cpg standalone run with --log-problems to see these parse issues.

@MC-box
Copy link
Author

MC-box commented Sep 19, 2024

I tried a c2cpg standalone run with --log-problems and found the following issue:

2024-09-18 22:42:25.906 INFO ParseProblemsLogger: Parse problem 'CASTProblem' occurred!
  Code: 'JNIEXPORT void JNICALL Java_com_termux_x11_XrActivity_teardown(JNIEnv *env, jobject obj) {
    if (!xr_initialized) {
        return;
    }

    XrRendererDestroy(&xr_engine, &xr_renderer);
    XrEngineLeave(&xr_engine);
    XrEngineDestroy(&xr_engine);

    memset(&xr_engine, 0, sizeof(xr_engine));
    memset(&xr_input, 0, sizeof(xr_input));
    memset(&xr_renderer, 0, sizeof(xr_renderer));
    xr_initialized = false;
    
}'
  File: '/home/kali/桌面/cfgtool/cfgtool/cfgtool_new/cfgtool_fix/c_termux-x11-master/android.c'
  Line: 8

It is too general to locate the bug. And I try to find information on 'CASTProblem' in joern's document but fail. I apologize for any inconvenience, but I would greatly appreciate it if you can provide some guidance.

@max-leuthaeuser
Copy link
Contributor

I am pretty sure the parser can't find the definitions for JNIEXPORT and JNICALL.
What happens if you place these definitions directly into the file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants