Using FUSE library with Java; trying to replicate hello.c example - java

I am trying to create bindings to the FUSE library using JNA, but I have hit a snag along the road. I have minimized the code as much as possible to make it digestible here.
The FUSE library comes with a few example filesystems written in C. The simplest of them is hello.c. The following is a minimized version of its code to simply a few prints in the filesystem functions:
hello.c:
/*
FUSE: Filesystem in Userspace
Copyright (C) 2001-2007 Miklos Szeredi <miklos#szeredi.hu>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
gcc -Wall hello.c -o hello `pkg-config fuse --cflags --libs`
*/
#define FUSE_USE_VERSION 26
#include <fuse.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
static int hello_getattr(const char *path, struct stat *stbuf)
{
printf("getattr was called\n");
return 0;
}
static int hello_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi)
{
printf("readdir was called\n");
return 0;
}
static int hello_open(const char *path, struct fuse_file_info *fi)
{
printf("open was called\n");
return 0;
}
static int hello_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
{
printf("read was called\n");
return 0;
}
static struct fuse_operations hello_oper = {
.getattr = hello_getattr,
.readdir = hello_readdir,
.open = hello_open,
.read = hello_read,
};
int main(int argc, char *argv[])
{
return fuse_main_real(argc, argv, &hello_oper, sizeof(hello_oper), NULL);
}
This can be compiled using gcc -Wall hello.c -o hello -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse -pthread -lfuse -lrt -ldl
And invoked with ./hello.c -f /some/mount/point
The -f flag is to make it stay in the foreground so that you can see the printf()'s working.
All of this works well, you can see the printf()'s executing properly. I am trying to replicate the same thing in Java using JNA. Here is what I came up with:
FuseTemp.java:
import com.sun.jna.Callback;
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
public class FuseTemp
{
public static interface Fuse extends Library
{
int fuse_main_real(int argc, String[] argv, StructFuseOperations op, long size, Pointer user_data);
}
#SuppressWarnings("unused")
public static class StructFuseOperations extends Structure
{
public static class ByReference extends StructFuseOperations implements Structure.ByReference
{
}
public Callback getattr = new Callback()
{
public int callback(final String path, final Pointer stat)
{
System.out.println("getattr was called");
return 0;
}
};
public Callback readlink = null;
public Callback mknod = null;
public Callback mkdir = null;
public Callback unlink = null;
public Callback rmdir = null;
public Callback symlink = null;
public Callback rename = null;
public Callback link = null;
public Callback chmod = null;
public Callback chown = null;
public Callback truncate = null;
public Callback utime = null;
public Callback open = new Callback()
{
public int callback(final String path, final Pointer info)
{
System.out.println("open was called");
return 0;
}
};
public Callback read = new Callback()
{
public int callback(final String path, final Pointer buffer, final long size, final long offset, final Pointer fi)
{
System.out.println("read was called");
return 0;
}
};
public Callback write = null;
public Callback statfs = null;
public Callback flush = null;
public Callback release = null;
public Callback fsync = null;
public Callback setxattr = null;
public Callback getxattr = null;
public Callback listxattr = null;
public Callback removexattr = null;
public Callback opendir = null;
public Callback readdir = new Callback()
{
public int callback(final String path, final Pointer buffer, final Pointer filler, final long offset,
final Pointer fi)
{
System.out.println("readdir was called");
return 0;
}
};
public Callback releasedir = null;
public Callback fsyncdir = null;
public Callback init = null;
public Callback destroy = null;
public Callback access = null;
public Callback create = null;
public Callback ftruncate = null;
public Callback fgetattr = null;
public Callback lock = null;
public Callback utimens = null;
public Callback bmap = null;
public int flag_nullpath_ok;
public int flag_reserved;
public Callback ioctl = null;
public Callback poll = null;
}
public static void main(final String[] args)
{
final String[] actualArgs = { "-f", "/some/mount/point" };
final Fuse fuse = (Fuse) Native.loadLibrary("fuse", Fuse.class);
final StructFuseOperations.ByReference operations = new StructFuseOperations.ByReference();
System.out.println("Mounting");
final int result = fuse.fuse_main_real(actualArgs.length, actualArgs, operations, operations.size(), null);
System.out.println("Result: " + result);
System.out.println("Mounted");
}
}
The definition of the the fuse_operations struct can be found here.
This can be compiled using: javac -cp path/to/jna.jar FuseTemp.java
And invoked using java -cp path/to/jna.jar:. FuseTemp
jna.jar is available here.
The error that comes up is: fusermount: failed to access mountpoint /some/mount/point: Permission denied.
I am executing both programs as the same user with the same permissions on the same mountpoint folder, and I am in the fuse group. I am using:
Linux kernel 3.0.0
FUSE 2.8.4
OpenJDK 1.6.0_23
JNA 3.4.0
So my question is: What exactly is different between these two programs (hello.c and FuseTemp.java), and how to make them do the same thing?
Thanks in advance.
Edit: Here is some additional info.
Initial stat of the mountpoint:
File: `/some/mount/point'
Size: 4096 Blocks: 8 IO Block: 4096 directory
Device: 803h/2051d Inode: 540652 Links: 2
Access: (0777/drwxrwxrwx) Uid: ( 1000/ myusername) Gid: ( 1000/ myusername)
Output I get from running the Java program as regular user:
Mounting
fusermount: failed to access mountpoint /some/mount/point: Permission denied
Result: 1
Mounted
(program exits with return code 0)
After this, trying to execute stat gives the following error message:
stat: cannot stat/some/mount/point': Transport endpoint is not connected`
That is because the Java program isn't running anymore, so fuse cannot call its callbacks. To unmount, if I try fusermount -u /some/mount/point, I get:
fusermount: entry for /some/mountpoint not found in /etc/mtab
And if I try sudo fusermount -u /some/mount/point, the mountpoint is successfully unmounted and there is no output from fusermount. /etc/mtab is chmod'd 644 (-rw-r--r--) so my user can read it, but it doesn't contain /some/mount/point. After a successful unmount, the mountpoint is back to its old permissions (777 directory).
Now, running the java program as root:
Mounting
Result: 1
Mounted
(program exits with return code 0)
After that, stating /some/mount/point shows that is has not been modified, i.e. it is still a 777 directory.
I have also rewritten FuseTemp.java to include all Callbacks as Callbacks instead of Pointers. The behavior is the same, however.
I looked at fuse's source code and the error code 1 can be returned at multiple points throughout the execution. I will pinpoint where exactly is it failing on the fuse side and report back here.
Now for hello.c: running it as regular user, starting with the same permissions on /some/mount/point and passing it the arguments -f and /some/mount/point, the program doesn't print any output at first but keeps running. When running stat on the mountpoint, the program prints
getattr was called
like it should. stat returns an error, but that's simply because hello.c's getattr function doesn't give it any information, so no problems there. After executing fusermount -u /some/mount/point as regular user, the program exits with return code 0 and the unmount is successful.
Running it as root, starting with the same permissions on /some/mount/point and passing it the arguments -f and /some/mount/point, the program doesn't print any output at first but keeps running. When running stat on the mountpoint, I get a permission error because I am not root. When running stat on it as root, the program prints
getattr was called
like it should. Executing fusermount -u /some/mount/point as regular user yields
fusermount: entry for /some/mount/point not found in /etc/mtab
Executing fusermount as root, the program exits with return code 0 and the unmount is successful.

Found it. While the error was really silly in retrospect, it wasn't easy to spot.
The solution: Fuse's fuse_main_real method's first argument is an argument list. In this list, it expects argument 0 to be the filesystem name, or some meaningful program name. Thus, instead of
final String[] actualArgs = { "-f", "/some/mount/point" };
It should have been
final String[] actualArgs = { "programName", "-f", "/some/mount/point" };
This also means that you can't use the argument list that Java gives you in your main method, since that doesn't include the program name either.
Why it matters: fuse actually does its own argument parsing and calls /bin/mount passing it the following arguments:
--no-canonicalize -i -f -t fuse.(arg 0) -o (options) (mountpoints) ...
As such, if you give if -f /some/mount/point as argument list, fuse will try to run:
/bin/mount --no-canonicalize -i -f -t fuse.-f -o rw,nosuid,nodev /some/mount/point
And mount doesn't like "fuse.-f" and will complain.
How it was found: Adding a bunch of printf() inside fuse's source code to figure out where exactly things were failing: in /lib/mount_util.c at line 82:
execl("/bin/mount", "/bin/mount", "--no-canonicalize", "-i",
"-f", "-t", type, "-o", opts, fsname, mnt, NULL);
I apologise for assuming the error was due to it being Java-related or JNA-related or permissions-related. I will edit the question title and tags to reflect this. (In my defense, the error fuse was returning ("Permission denied") certainly wasn't helpful!)
Thank you for your assistance ee. and technomage, and again I apologise for taking away a chunk of your time because of what turned out to be a silly mistake.

Regarding the permission denied issue when running the jar...I am sure it is Java security permission thing is going on here to explain why no exception is caught when running in superuser mode but permission denied exception is caught when running in non-superuser mode.
From what I can understand, Java has a layer of security unlike the standard C program (except for some C libraries that may include security checks, just like .NET managed C++ libraries). Even though the file manipulation functions are coming from libfuse.so, it may also call Linux system kernel calls that may be executed within system kernel memory space. Since it is now running via Java where Java has to load/map all library functions including system calls into memory. If Java finds out the memory map occurs in system kernel memory space rather than user memory space during execution, it will refer its security manager to check against the current user state of the Java program.
Otherwise, the permission denied error may actually come from fuse trying to access a mount point that is restricted from the normal user which is an expected behavior. Then, this has nothing to do with Java. But, this error shall also occur in C program as well. But, from your post and comments, it doesn't tell that much.
However, running the program as root didn't cause the error to appear.
Alas, it didn't seem to do anything: It just said "Mounting" and
"Mounted" instantly. So it does go up to completion, but the
fuse_main_real call returns instantly. The number it returns is 1.
That is some progress, but the program needs to be runnable as a
regular user like hello.c can.
On the other hand, based on your recent comment above, it seems that your function pointer (callback) fields in StructFuseOperations structure are not working to "fire up" any fuse event that fuse may invoke.
Note: I assume that the "erroneous" main Java program displays "Mounting" and "Mounted" and nothing else in between them which actually involves a call to fuse_main_real method that doesn't fire up any fuse event but a return code of 1 when running the program in the superuser mode. I haven't tried the code in the post since I don't have access to Linux OS right now.
Update: from this point onwards, the discussion about callback padding in a JNA structure is no longer valid after the recent post update made by OP: https://stackoverflow.com/revisions/e28dc30b-9b71-4d65-8f8a-cfc7a3d5231e/view-source
Based on the given link, fuse_operations Struct Reference, you only focus on a few fields of the C structure as follows:
static struct fuse_operations hello_oper = {
int (getattr*)(const char *path, struct stat *stbuf);
/** some 12 skipped callbacks in between **/
int (open*)(const char *path, struct fuse_file_info *fi);
int (read*)(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
/** some 10 skipped callbacks in between **/
int (readdir*)(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi);
/** some 11 skipped callbacks in between **/
unsigned int flag_nullpath_ok;
unsigned int flag_reserved;
/** some 2 skipped callbacks in between **/
};
However, it seems that you are trying to skip a few callback fields with padding. Therefore, to maintain the order of how the callback fields are laid out in fuse_operations structure, you apply the Pointer type to each callback field that you have skipped. However, by assuming a simple Pointer field for these skipped structure fields, you have removed the vital information about the callback for each field: its callback signature.
From JNA API Overview:
Callbacks (Function Pointers)
JNA supports supplying Java callbacks to native code. You must define
an interface that extends the Callback interface, and define a single
callback method with a signature that matches the function pointer
required by the native code. The name of the method may be something
other than "callback" only if there is only a single method in the
interface which extends Callback or the class which implements
Callback. The arguments and return value follow the same rules as for
a direct function invocation.
If the callback returns a String or String[], the returned memory will
be valid until the returned object is GC'd.
Following is what is suggested in the overview:
// Original C code
struct _functions {
int (*open)(const char*,int);
int (*close)(int);
};
// Equivalent JNA mapping
public class Functions extends Structure {
public static interface OpenFunc extends Callback {
int invoke(String name, int options);
}
public static interface CloseFunc extends Callback {
int invoke(int fd);
}
public OpenFunc open;
public CloseFunc close;
}
...
Functions funcs = new Functions();
lib.init(funcs);
int fd = funcs.open.invoke("myfile", 0);
funcs.close.invoke(fd);
However, it doesn't suggest a way to properly skip the callbacks with padding technique in a structure especially when it is too large and you don't want to define every callback that you are not interested with. Maybe, it is not warranted and may cause undefined behavior like what you are facing...
Probably, instead of Pointer for each callback field that you want to pad, you can use Callback field, maintain its field name as in the specification. You may or may not initialize it with the null value (I haven't tried this; possibly it may not work).
Update:
It seems that my suggestion above can work based on the unrelated JNA solution by tgdavies in C callback with JNA makes JRE crash where he padded those callback fields he wasn't interested with simple Callback type but the matching callback field names remained intact in the sp_session_callbacks Structure.
I guess, because of the improper fuse_operations structure, fuse_main_real is unable to fire up the expected fuse event that you are interested with.

Related

JNIEnv::NewObject() throwing java.lang.InstantiantionException

I am attempting to call JNIEnv::NewObject() in some JNI code when a C function returns a non-zero error code.
The order of events looks like:
Call C function.
If return code is non-zero, call a helper function which throws a custom excpetion.
The class I am trying to construct so that I can throw it is:
public final class HseException extends Exception {
private static final long serialVersionUID = 8995408998818557762L;
private final int errno;
private final Context ctx;
/* Only called from C */
HseException(final String message, final int errno, final Context ctx) {
super(message);
this.errno = errno;
this.ctx = ctx;
}
public Context getContext() {
return this.ctx;
}
public int getErrno() {
return this.errno;
}
public static enum Context {
NONE
}
}
In my code I am caching the jclass and jmethodID for the class and the constructor in a global struct, but the code looks like:
globals.com.micron.hse.HseException.class =
(*env)->FindClass(env, "com/micron/hse/HseException");
globals.com.micron.hse.HseException.init = (*env)->GetMethodID(
env,
globals.com.micron.hse.HseException.class,
"<init>",
"(Ljava/lang/String;ILcom/micron/hse/HseException$Context;)V");
globals.com.micron.hse.HseException.Context.class =
(*env)->FindClass(env, "com/micron/hse/HseException$Context");
globals.com.micron.hse.HseException.Context.NONE = (*env)->GetStaticFieldID(
env,
globals.com.micron.hse.HseException.Context.class,
"NONE",
"Lcom/micron/hse/HseException$Context;");
Note that the above code is located in the JNI_OnLoad() function of my library. This function completes without error, so this tells me that at least my classes and methods are being loaded correctly.
Lastly here is my helper function where I throw my custom exception type:
/* hse_err_t is a scalar type.
* hse_strerror() creates a string out of that scalar.
* hse_err_to_ctx() gets the enum context value embedded within the scalar.
* hse_err_to_errno() gets the errno value embedded within the scalar.
*/
jint
throw_new_hse_exception(JNIEnv *env, hse_err_t err)
{
assert(env);
assert(err);
const size_t needed_sz = hse_strerror(err, NULL, 0);
char *buf = malloc(needed_sz + 1);
if (!buf)
return (*env)->ThrowNew(
env,
globals.java.lang.OutOfMemoryError.class,
"Failed to allocate memory for error buffer");
hse_strerror(err, buf, needed_sz + 1);
const jstring message = (*env)->NewStringUTF(env, buf);
free(buf);
if ((*env)->ExceptionCheck(env))
return JNI_ERR;
const int rc = hse_err_to_errno(err);
const enum hse_err_ctx ctx = hse_err_to_ctx(err);
jfieldID err_ctx_field = NULL;
switch (ctx) {
case HSE_ERR_CTX_NONE:
err_ctx_field = globals.com.micron.hse.HseException.Context.NONE;
break;
}
assert(err_ctx_field);
const jobject err_ctx_obj = (*env)->GetStaticObjectField(
env, globals.com.micron.hse.HseException.Context.class, err_ctx_field);
if ((*env)->ExceptionCheck(env))
return JNI_ERR;
const jobject hse_exception_obj = (*env)->NewObject(
env,
globals.com.micron.hse.HseException.class,
globals.com.micron.hse.HseException.init,
message,
rc,
err_ctx_obj);
if ((*env)->ExceptionCheck(env))
return JNI_ERR;
return (*env)->Throw(env, (jthrowable)hse_exception_obj);
}
I know for a fact that the (*env)->NewObject() call is what is raising the exception because an exception check before and after will tell me so. The (*env)->NewStringUTF() call is successful and contains the string it should contain. The context field is also retrieved successfully.
What I am not understanding is why I am getting an InstantiationException. The Throws section of the JNIEnv::NewObject() is marked as the following:
THROWS:
InstantiationException: if the class is an interface or an abstract class.
OutOfMemoryError: if the system runs out of memory.
Any exceptions thrown by the constructor.
My class is not an interface nor is it an abstract class, so where could this exception be generated from? The weird thing is that I swear this worked before, but since I am writing these Java bindings from scratch, I have just been overwriting commits and force pushing to my branch.
Any help is appreciated. Unfortunately getMessage() on the exception returns null which just isn't helpful at all. There is no message from the JVM telling me potentially what I have done wrong either.
One detail that could be helpful is that when I try to call JNIEnv::ThrowNew() (after putting a (Ljava/lang/String;)V constructor in the same HseException class, jni_ThrowNew() segfaults, and I cannot understand why. The class is valid when I stash the jclass, and I know for a fact that the memory it is stashed in isn't overwritten in any way, since I have checked the pointer.
The repo where all this code lives is: https://github.com/hse-project/hse-java. Unfinished product, but at least it is buildable and tests can be ran. In the event that someone decides to clone the repo and build it, I will repeat the directions here:
meson build
ninja -C build
meson test -C build -t 0 KvsTest # I am using this test to exercise the code path
My goal tomorrow will be to try to reproduce the issue in a smaller manner. I may also try to peer into the OpenJDK code assuming that is where the JNI interfaces live. Figure if I look hard enough, I might find the line of code which generates the exception.
Edit: I did a test where in my current code, I added a main function and a native function whose only purpose is to throw an exception from C. The code looks something like:
private static native void throwException();
public static void main(String[] args) {
System.load("/path/to/.so");
throwException();
}
The implementation of the native function is:
void Java_com_micron_hse_Hse_throwException
(JNIEnv *env, jclass hse_cls)
{
(void)hse_cls;
/* Generate error */
hse_err_t err = hse_kvdb_txn_begin(NULL, NULL);
throw_new_hse_exception(env, err);
}
This printed the following after executing java -jar path/to/jar:
Exception in thread "main" com.micron.hse.HseException: lib/binding/kvdb_interface.c:1046: Invalid argument (22)
at com.micron.hse.Hse.throwException(Native Method)
at com.micron.hse.Hse.main(Hse.java:28)
That is exactly what I expect to be printed, so now I would say I am even more lost than when I started. For some reason in the context of my tests, the InstantiationException is raised. Not sure if an application using the JAR would hit the same issue or if it is just a test context thing.
Edit 2:
Changed the main method from the previous edit to the following which is pretty much exactly what my test does:
public static void main(String[] args) throws HseException {
try {
loadLibrary(Paths.get("/home/tpartin/Projects/hse-java/build/src/main/c/libhsejni-2.so"));
init();
final Kvdb kvdb = Kvdb.open(Paths.get("/media/hse-tests"));
final Kvs kvs = kvdb.kvsOpen("kvs");
kvs.delete((byte[])null);
kvs.close();
kvdb.close();
} finally {
// fini();
}
}
And was able throw the exception from C appropriately. This must mean that something is wrong with my test environment somehow.
Edit 3: Another clue. On one test, this issue generates the InstantiationException. On another test, this issue segfaults in jni_NewObject.
My issue was that I was holding onto jclass et al. references for too long.
Prior question: Why I should not reuse a jclass and/or jmethodID in JNI?
Java docs: https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html#global_and_local_references
All Java objects returned by JNI functions are local references.
Thanks to Andrew Henle for pointing this out in the comments of the question. I have highlighted his comment in this answer, and will mark it is as the answer.

Getting base address of dll of specific process using JNA

Updated: See updates at the bot of the question
I would like to get base address of game.dll which is inside war3.exe process.
I'm trying to do it via JNA library version 5.9.0, but no success.
The issue I faced with: I can't get game.dll module from war3.exe process.
I tried to get it using:
int pid = getProcessId("Warcraft III");
openProcess(PROCESS_ALL_ACCESS, pid);
WinDef.HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle("game.dll")
But the result of hMod is null.
Also I have tried to get all modules that war3.exe process has. As you may see it contains only 5 modules and it doesn't contain game.dll. But when I open war3.exe via Process Explorer I see definitely more than 5.
Executed with Intellij Idea:
Taken from Process Explorer:
Please, share your opinion and ideas why I get only 5 modules from IDE.
Any advice on how to get the game.dll module and its base address via JNA would be appreciated.
Updates:
As per Remy's answer I have made one more try with EnumProcessModules().
Here is my code snippet:
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Psapi;
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinDef.HMODULE;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import java.util.Arrays;
import java.util.List;
import static com.sun.jna.platform.win32.WinNT.PROCESS_ALL_ACCESS;
import static handler.memory.MemoryHandler.openProcess;
public class MemoryHandler {
static final User32 user32 = User32.INSTANCE;
static final Psapi psapi = Psapi.INSTANCE;
public static void main(String[] args) {
int pid = getProcessId("Warcraft III");
HANDLE process = openProcess(PROCESS_ALL_ACCESS, pid);
HMODULE[] hMods = new HMODULE[1024];
psapi.EnumProcessModules(process, hMods, hMods.length, new IntByReference(1024));
List<HMODULE> hModList = Arrays.asList(hMods);
hModList.forEach(hMod ->
System.out.println(Pointer.nativeValue(hMod.getPointer())));
}
public static int getProcessId(String window) {
IntByReference pid = new IntByReference(0);
user32.GetWindowThreadProcessId(user32.FindWindow(null, window), pid);
return pid.getValue();
}
}
And here is the result:
As far as I understand I have got some pointers. But how should I understand which one from them is related to game.dll? I was assuming that I should get somehow the list on modules where I could see their names and base addresses.
Also if I change System.out.println(Pointer.nativeValue(hMod.getPointer()))); to hModList.forEach(System.out::println); I see the following pointers and a lot of nulls (about 1000).
Do these addresses contain the address of game.dll?
GetModuleHandle() looks in the calling process only. Since game.dll is not loaded in your own process, GetModuleHandle() can't find it.
To look for a module loaded in another process, you need to use either:
EnumProcessModules()/EnumProcessModulesEx(), using GetModuleFileNameEx() to get their file names. See Enumerating All Modules for a Process.
CreateToolhelp32Snapshot(TH32CS_SNAPMODULE|TH32CS_SNAPMODULE32), using Module32First()/Module32Next() to enumerate the snapshot. See Traversing the Module List.
Kernel32Utils.getModules() uses CreateToolhelp32Snapshot(TH32CS_SNAPMODULE), so if your Java app is running as a 64bit app then it will enumerate only 64bit modules. But war3.exe is running as a 32bit process in your screenshot, so if you use CreateToolhelp32Snapshot() in a 64bit process then you would need to use TH32CS_SNAPMODULE32 instead.
UPDATE:
As I mentioned above, if you go the EnumProcessModules() approach, you can use GetModuleFileNameEx() to determine the filename of each module. That way, you can find the module for game.dll.
More importantly:
you are lacking needed error handling of each system call. Always test return values for failures.
not an error per-se, but you really should not be requesting PROCESS_ALL_ACCESS rights with openProcess(). Request only the rights you actually need, no more. In this case, use PROCESS_QUERY_INFORMATION | PROCESS_VM_READ instead.
you are not looking at the output of the 4th parameter of EnumProcessModules() to know how many modules were actually stored in the array.
your input values of the 3rd and 4th parameters of EnumProcessModules() are wrong, they need to be expressed in bytes, not in elements.
Per the EnumProcessModules() documentation:
cb
The size of the lphModule array, in bytes.
lpcbNeeded
The number of bytes required to store all module handles in the lphModule array.
...
It is a good idea to specify a large array of HMODULE values, because it is hard to predict how many modules there will be in the process at the time you call EnumProcessModules. To determine if the lphModule array is too small to hold all module handles for the process, compare the value returned in lpcbNeeded with the value specified in cb. If lpcbNeeded is greater than cb, increase the size of the array and call EnumProcessModules again.
To determine how many modules were enumerated by the call to EnumProcessModules, divide the resulting value in the lpcbNeeded parameter by sizeof(HMODULE).
Finally I found solution, but not in Java or JNA.
I wrote this code using C++ and I will use it like dll in Java.
Here is my C++ code:
#include <conio.h>
#include <iostream>
#include <Windows.h>
#include <TlHelp32.h>
#include <psapi.h>
using namespace std;
DWORD_PTR GetProcessBaseAddress(DWORD processID)
{
DWORD_PTR baseAddress = 0;
HANDLE processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
HMODULE* moduleArray;
LPBYTE moduleArrayBytes;
DWORD bytesRequired;
if (processHandle)
{
if (EnumProcessModules(processHandle, NULL, 0, &bytesRequired))
{
if (bytesRequired)
{
moduleArrayBytes = (LPBYTE)LocalAlloc(LPTR, bytesRequired);
if (moduleArrayBytes)
{
unsigned int moduleCount;
moduleCount = bytesRequired / sizeof(HMODULE);
moduleArray = (HMODULE*)moduleArrayBytes;
if (EnumProcessModules(processHandle, moduleArray, bytesRequired, &bytesRequired))
{
baseAddress = (DWORD_PTR)moduleArray[0];
}
LocalFree(moduleArrayBytes);
}
}
}
CloseHandle(processHandle);
}
return baseAddress;
}
DWORD GetProcessId(LPCTSTR ProcessName) // non-conflicting function name
{
PROCESSENTRY32 pt;
HANDLE hsnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
pt.dwSize = sizeof(PROCESSENTRY32);
if (Process32First(hsnap, &pt)) { // must call this first
do {
if (!lstrcmpi(pt.szExeFile, ProcessName)) {
CloseHandle(hsnap);
return pt.th32ProcessID;
}
} while (Process32Next(hsnap, &pt));
}
CloseHandle(hsnap); // close handle on failure
return 0;
}
uintptr_t GetModuleBaseAddress(DWORD procId, const wchar_t* modName)
{
uintptr_t modBaseAddr = 0;
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, procId);
if (hSnap != INVALID_HANDLE_VALUE)
{
MODULEENTRY32 modEntry;
modEntry.dwSize = sizeof(modEntry);
if (Module32First(hSnap, &modEntry))
{
do
{
if (!_wcsicmp(modEntry.szModule, modName))
{
modBaseAddr = (uintptr_t)modEntry.modBaseAddr;
break;
}
} while (Module32Next(hSnap, &modEntry));
}
}
CloseHandle(hSnap);
return modBaseAddr;
}
int main()
{
DWORD pid = GetProcessId(TEXT("war3.exe"));
cout << "Process ID of war3.exe: "<< pid << endl;
DWORD_PTR war3_exe_base_addr = GetProcessBaseAddress(pid);
cout <<"Base address of war3.exe: "<< war3_exe_base_addr << endl;
uintptr_t gameDllBaseAddress = GetModuleBaseAddress(pid, TEXT("game.dll"));
cout <<"Base address of game.dll: " << gameDllBaseAddress << endl;
}
The result is:

Java JNA call to function "InitiateSystemShutdown" in dll Advapi32 don't work

I have this call to the function "InitiateSystemShutdown" of the Advapi32 dll with java jna but it didn't work:
public interface JNAApiInterface extends StdCallLibrary {
JNAApiInterface INSTANCE = (JNAApiInterface) Native.loadLibrary("Advapi32", JNAApiInterface.class);
public boolean InitiateSystemShutdown(String machine, String message, short timeout, boolean forceAppClose, boolean rebootAfterShutdown);
}
public class JNABucket {
public static void main(String args[]) {
System.setProperty("jna.library.path", "C:\\Windows\\System32");
JNAApiInterface jnaLib = JNAApiInterface.INSTANCE;
jnaLib.InitiateSystemShutdown(null, null, (short)0, true, true);
}
}
The error is:
Exception in thread "main" java.lang.UnsatisfiedLinkError: Error looking up
function 'InitiateSystemShutdown': No se encontrĂ³ el proceso especificado.
at com.sun.jna.Function.<init>(Function.java:179)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:430)
at com.sun.jna.NativeLibrary.getFunction(NativeLibrary.java:410)
at com.sun.jna.Library$Handler.invoke(Library.java:205)
at com.sun.proxy.$Proxy0.InitiateSystemShutdown(Unknown Source)
at es.tecnocom.pruebas.JNABucket.main(JNABucket.java:9)
Someone can help me?
If after changing the funcion to "InitiateSystemShutdownA" or "InitiateSystemShutdownW" still isn't working, it's probably a permissions issue, as #cubrr suggested.
Try adding this:
HANDLEByReference hToken = new HANDLEByReference();
LUID luid = new LUID();
Advapi32.INSTANCE.OpenProcessToken(Kernel32.INSTANCE.GetCurrentProcess(), WinNT.TOKEN_ADJUST_PRIVILEGES, hToken);
Advapi32.INSTANCE.LookupPrivilegeValue("", WinNT.SE_SHUTDOWN_NAME, luid);
TOKEN_PRIVILEGES tp = new TOKEN_PRIVILEGES(1);
tp.Privileges[0] = new LUID_AND_ATTRIBUTES(luid, new DWORD(WinNT.SE_PRIVILEGE_ENABLED));
Advapi32.INSTANCE.AdjustTokenPrivileges(hToken.getValue(), false, tp, tp.size(), null, new IntByReference());
just before this call to the function:
jnaLib.InitiateSystemShutdown(null, null, (short)0, true, true);
If you take a look at the documentation page for InitiateSystemShutdown, you'll notice at the bottom that the actual function names are InitiateSystemShutdownW (Unicode) and InitiateSystemShutdownA (ANSI). Most (all?) WinAPI functions which deal with strings are defined as preprocessor symbols which resolve to either the *A or *W ending function, depending on whether UNICODE is defined at compile time.
Example from Working with Strings:
#ifdef UNICODE
#define SetWindowText SetWindowTextW
#else
#define SetWindowText SetWindowTextA
#endif
Rename your function to InitiateSystemShutdownA or InitiateSystemShutdownW, depending on which encoding you want to use. I've personally always used the ANSI variants, so I don't know if you need to specify the Unicode encoding manually if you go with the *W variant.
public interface JNAApiInterface extends StdCallLibrary {
JNAApiInterface INSTANCE = (JNAApiInterface) Native.loadLibrary("Advapi32", JNAApiInterface.class);
public boolean InitiateSystemShutdownA(String machine, String message, short timeout, boolean forceAppClose, boolean rebootAfterShutdown);
}
Notice also that you need certain privileges to restart a computer. Excerpt from the documentation:
To shut down the local computer, the calling thread must have the SE_SHUTDOWN_NAME privilege. To shut down a remote computer, the calling thread must have the SE_REMOTE_SHUTDOWN_NAME privilege on the remote computer. By default, users can enable the SE_SHUTDOWN_NAME privilege on the computer they are logged onto, and administrators can enable the SE_REMOTE_SHUTDOWN_NAME privilege on remote computers. For more information, see Running with Special Privileges.
Common reasons for failure include an invalid or inaccessible computer name or insufficient privilege. The error ERROR_SHUTDOWN_IN_PROGRESS is returned if a shutdown is already in progress on the specified computer. The error ERROR_NOT_READY can be returned if fast-user switching is enabled but no user is logged on.

JNA: How use CreateProcess for execute 32 bit version of a system native app in 64 bit systems?

I have a application that uses JNA for execute any other application using CreateProcess api. This works very fine, but when i need execute a 32 bit version of a system native app, is executing 64 bit version ( present on SysWOW64 folder ), for example: notepad.exe 64 bit.
So, exist some way for solve this troube?
I had tried use Wow64DisableWow64FsRedirection but seem don't is working.
My code:
Execute class:
import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.WString;
import static com.sun.jna.platform.win32.WinBase.STARTF_USESHOWWINDOW;
import static com.sun.jna.platform.win32.WinUser.SW_HIDE;
import com.sun.jna.win32.StdCallLibrary;
import java.util.Arrays;
import java.util.List;
public class Execute {
public interface Kernel32 extends StdCallLibrary {
Kernel32 INSTANCE = (Kernel32) Native.loadLibrary("kernel32", Kernel32.class);
boolean CreateProcessA(
String lpApplicationName
, String lpCommandLine
, Structure lpProcessAttributes
, Structure lpThreadAttributes
, boolean bInheritHandles
, int dwCreationFlags
, Structure lpEnvironment
, String lpCurrentDirectory
, Structure lpStartupInfo
, Structure lpProcessInformation);
}
public static class ProcessInformation extends Structure {
public Pointer hProcess;
public Pointer hThread;
public int dwProcessId;
public int dwThreadId;
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[] { "hProcess", "hThread", "dwProcessId", "dwThreadId" });
}
}
public static class StartupInfoA extends Structure {
public int cb;
public WString lpReserved;
public WString lpDesktop;
public WString lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public Pointer lpReserved2;
public Pointer hStdInput;
public Pointer hStdOutput;
public Pointer hStdError;
#Override
protected List getFieldOrder() {
return Arrays.asList(new String[] { "cb", "lpReserved", "lpDesktop", "lpTitle", "dwX", "dwY", "dwXSize", "dwYSize", "dwXCountChars", "dwYCountChars", "dwFillAttribute", "dwFlags", "wShowWindow", "cbReserved2", "lpReserved2", "hStdInput", "hStdOutput", "hStdError" });
}
}
public static void ExecuteProc(String software){
ProcessInformation processInformation = new ProcessInformation();
StartupInfoA startupInfo = new StartupInfoA();
startupInfo.dwFlags = STARTF_USESHOWWINDOW;
startupInfo.wShowWindow = SW_HIDE;
Kernel32.INSTANCE.CreateProcessA(software, null
, null
, null
, true
, 0
, null
, "C:\\Windows\\System32\\"
, startupInfo
, processInformation);
}
}
Main:
public static native boolean Wow64DisableWow64FsRedirection(PointerByReference OldValue);
public static void Exec() {
PointerByReference lpBuffer = new PointerByReference();
Wow64DisableWow64FsRedirection(lpBuffer); // fails here
String sysdir = System.getenv("WINDIR") + "\\System32\\";
ExecuteProc(sysdir + "notepad.exe");
}
--- Updated because Windows is well, Windows ---
32 bit executables are in SysWOW64, while 64 bit executables are in System32. Apparently this bizarre choice makes sense to the people up in Redmond.
--- Rest of post follows, with updates ---
You are asking a 64 bit program to load and interface with 32 bit executables. The "compatibility" for 32 bit executables doesn't extend to linking them to 64 bit programs.
You need to launch a 32 bit JVM so the JNI interface will match the desired environment.
However, your example might not even need JNI. If you are launching 32-bit standalone programs, then you do not need to use JNI. Instead you could use ProcessBuilder and pass the command line arguments to the shell to effectively ensure you launch the 32 bit executable.
ProcessBuilder pb = new ProcessBuider(String.format("%s\\SysWOW64\\notepad.exe", System.getEnv("WINDIR"));
Process process = pb.start();
JNI is for when you need to link the JVM to native libraries, it is not the preferred way to launch native applications. ProcessBuilder is what you prefer to launch native applications.
This may not be appropriate for your set-up depending on what your needs are, but at my company we had this problem when we moved to a 64-bit operating system for our terminal server and we had an in-house Java application that required the 32-bit version of Java to run properly.
My solution was to go into the 64-bit java directory, rename java.exe and javaw.exe to java.exe.bak and javaw.exe.bak, respectively, then replace those files with stubs that launched the 32-bit version of Java instead. This was acceptable in our case since we only have one application that uses Java and we did not foresee ourselves writing any more applications in Java going forward:
// Stub file that launches the 32-bit java.exe
// Intended to replace the 64-bit java executable to ensure that (OUR APPLICATION) which only works with 32-bit java works correctly
// Author: Govind Parmar
#include <Windows.h>
#include <strsafe.h>
HRESULT __cdecl cat_argv(int argc, WCHAR *argv[], WCHAR *argstr, int cchargstr)
{
int i;
HRESULT hr;
ZeroMemory(argstr, sizeof(WCHAR) * cchargstr);
// first arg is program name; start with i=1 instead of 0
for (i = 1; i < argc; i++)
{
// Space out arguments
hr = StringCchCat(argstr, cchargstr, L" ");
if (FAILED(hr)) break;
hr = StringCchCat(argstr, cchargstr, argv[i]);
if (FAILED(hr)) break;
}
return hr;
}
int __cdecl wmain(int argc, WCHAR *argv[])
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
WCHAR args[8192];
DWORD dwExit;
ZeroMemory(&si, sizeof(STARTUPINFO));
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
si.cb = sizeof(STARTUPINFO);
if (FAILED(cat_argv(argc, argv, args, 8192)))
{
_putws(L"Could not concatenate argument string!");
return 0;
}
CreateProcess(L"C:\\Program Files (x86)\\Java\\jre1.8.0_101\\bin\\java.exe", args, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, NULL, L"C:\\Program Files (x86)\\Java\\jre1.8.0_101\\bin\\", &si, &pi);
WaitForSingleObject(pi.hProcess, INFINITE);
GetExitCodeProcess(pi.hProcess, &dwExit);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return dwExit;
}

Getting text data from C++ using JNI through std::ostream into Java

I have a class in C++ which takes an std::ostream as an argument in order to continuously output text (trace information). I need to get this text over to the Java side as efficiently as possible. What's the best way to do this? I was thinking of using a direct buffer, but another method would be to take all the function calls across to Java and do all the processing there, but it seems that I'd need a lot of JNI calls.
If an example could be shown of the exact implementation method, it would be very helpful, or if some code exists already to do this (perhaps part of another project). Another help would be to connect it up directly to a standard Java streaming construct, such that the entire implementation was completely transparent to the developer.
(Edit: I found Sharing output streams through a JNI interface which seems to be a duplicate, but not really of much help -- he didn't seem to find the answer he was looking for)
The std::ostream class requires a std::streambuf object for its output. This is used by the fstream and stringstream classes, which use the features of ostream by providing a custom implementation of the streambuf class.
So you can write your own std::streambuf implementation with an overwritten overflow method, buffer the incomming chars in an internal stringbuffer. Every x calls or on eof/newline generate an java-string and call the print method of your java PrintStream.
An incomplete example class:
class JavaStreamBuff : std::streambuf
{
std::stringstream buff;
int size;
jobject handle;
JNIEnv* env
//Ctor takes env pointer for the working thread and java.io.PrintStream
JavaStreamBuff(JNIEnv* env, jobject jobject printStream, int buffsize = 50)
{
handle = env->NewGlobalRef(printStream);
this->env = env;
this->size = size;
}
//This method is the central output of the streambuf class, every charakter goes here
int overflow(int in)
{
if(in == eof || buff.size() == size)
{
std::string blub = buff.str();
jstring do = //magic here, convert form current locale unicode then to java string
jMethodId id = env->(env->GetObjectClass(handle),"print","(java.lang.String)V");
env->callVoidMethod(id,handle,do);
buff.str("");
}
else
{buff<<in;}
}
virtual ~JavaStreamBuff()
{
env->DeleteGlobalRef(handle);
}
}
Missing:
Multithread support (the env pointer is only valid for the jvm thread)
Error handling (checking for java exceptions thrown)
Testing(written within the last 70 min)
Native java method to set the printstream.
On the java side you need a class to convert the PrintStream to a BufferedReader.
There have to be some bugs there, haven't spend enough time to work on them.
The class requires all access to be from the thread it was created in.
Hope this helps
Note
I got it to work with visual studio but I can't get it to work with g++, will try to debug that later.
Edit
Seems that I should have looked for a more official tutorial on this bevore posting my answer, the MSDN page on this topic derives the stringbuffer in a different way.
Sorry for posting this without testing it better :-(.
A small correction to the code above in a more or less unrelated point: Just implement InputStream with a custom class and push byte[] arrays instead of Strings from c++.
The InputStream has a small interface and a BufferedReader should do most of the work.
Last update on this one, since im unable to get it to work on linux, even with the comments on the std::streambuf class stating that only overflow has to be overwritten.
This implementation pushes the raw strings into an inputstream, which can be read from by an other thread. Since I am too stupid to get the debugger working its untested, again.
//The c++ class
class JavaStreamBuf :public std::streambuf
{
std::vector<char> buff;
unsigned int size;
jobject handle;
JNIEnv* env;
public:
//Ctor takes env pointer for the working thread and java.io.PrintStream
JavaStreamBuf(JNIEnv* env, jobject cppstream, unsigned int buffsize = 50)
{
handle = env->NewGlobalRef(cppstream);
this->env = env;
this->size = size;
this->setbuf(0,0);
}
//This method is the central output of the streambuf class, every charakter goes here
virtual int_type overflow(int_type in = traits_type::eof()){
if(in == std::ios::traits_type::eof() || buff.size() == size)
{
this->std::streambuf::overflow(in);
if(in != EOF)
buff.push_back(in);
jbyteArray o = env->NewByteArray(buff.size());
env->SetByteArrayRegion(o,0,buff.size(),(jbyte*)&buff[0]);
jmethodID id = env->GetMethodID(env->GetObjectClass(handle),"push","([B)V");
env->CallVoidMethod(handle,id,o);
if(in == EOF)
env->CallVoidMethod(handle,id,NULL);
buff.clear();
}
else
{
buff.push_back(in);
}
return in;
}
virtual ~JavaStreamBuf()
{
overflow();
env->DeleteGlobalRef(handle);
}
//The java class
/**
*
*/
package jx;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InterruptedIOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* #author josefx
*
*/
public class CPPStream extends InputStream {
List<Byte> data = new ArrayList<Byte>();
int off = 0;
private boolean endflag = false;
public void push(byte[] d)
{
synchronized(data)
{
if(d == null)
{
this.endflag = true;
}
else
{
for(int i = 0; i < d.length;++i)
{
data.add(d[i]);
}
}
}
}
#Override
public int read() throws IOException
{
synchronized(data)
{
while(data.isEmpty()&&!endflag)
{
try {
data.wait();
} catch (InterruptedException e) {
throw new InterruptedIOException();
}
}
}
if(endflag)return -1;
else return data.remove(0);
}
}
Sorry for wasting so much space^^(and time :-().
It sounds as though the deliverable here is a subclass of ostream. The immediate question I'd want to be clear about is, will this class be responsible for buffering data until Java calls into it to retrieve, or is it expected to immediately (synchronously?) call via JNI to pass it on? That will be the strongest guide to how the code will shape up.
If you can reasonably expect the text to appear as a series of lines, I'd think about presenting them to Java in one line per call: this seems a fair compromise between the number of JNI calls and not unduly delaying the passing on of the text.
On the Java side I think you're looking at creating a Reader so that clients can pick up the text via a familiar interface, or perhaps a subclass of BufferedReader.

Categories

Resources