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

Plugins: Determine correct pointer size automatically, without the need of specific headers and variables #3262

Conversation

davidebeatrici
Copy link
Member

No description provided.

@davidebeatrici davidebeatrici force-pushed the plugins-automatic-architecture-detection branch 3 times, most recently from 7bb33c2 to a601e52 Compare November 12, 2017 22:08
@davidebeatrici davidebeatrici changed the title Plugins: automatic process architecture detection Plugins: Determine correct pointer size automatically, without the need of specific headers and variables Nov 12, 2017
@davidebeatrici davidebeatrici force-pushed the plugins-automatic-architecture-detection branch from a601e52 to 222298c Compare November 13, 2017 00:42
@davidebeatrici davidebeatrici force-pushed the plugins-automatic-architecture-detection branch 2 times, most recently from 4ad5944 to 755b853 Compare November 13, 2017 19:45
Copy link
Contributor

@hacst hacst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes the code quite a bit more convenient. Not exactly fond of the linux way of checking for 64bit but that probably can't be helped if we want this feature.

See comments.

@@ -23,7 +19,8 @@
#include "mumble_plugin.h"

pid_t pPid;
static PTR_TYPE_CONCRETE pModule;
bool is64Bit;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no bool in C

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should create an enum.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually... no. It's better if we change the variable to an integer, otherwise we can't use the inline if statement.

@@ -23,7 +19,8 @@
#include "mumble_plugin.h"

pid_t pPid;
static PTR_TYPE_CONCRETE pModule;
bool is64Bit;
static procptr_t pModule;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this is static to be honest. We only include it in one TU and having it multiple times would almost always lead to mistakes as you'd have to initialize is separately from each TU. Without static at least the linker would complain. Any ideas?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked myself too why this is static, but I decided to left it as it was.

std::ifstream ifs;
ifs.open(ss.str(), std::ifstream::binary);

std::string elf;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

istreams have a read method that does what you want (http://www.cplusplus.com/reference/istream/istream/read/):

char elf[5];
ifs.read(elf, 5);

Don't forget to check whether the stream is ok after than.

ifs.close();

if (!(elf.at(0) == 0x7f && elf.at(1) == 'E' && elf.at(2) == 'L' && elf.at(3) == 'F')) {
return -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does -1 indicate failure to identify then? Please document the function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right.

if (!hProcess) {
int result = checkProcessIs64Bit(hProcess);
if (result == -1) {
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaking hProcess?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think it's better if we create a dedicated handle in checkProcessIs64Bit(), so that the global one needs only PROCESS_VM_READ.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That just gives us another handle that we mustn't leak ;) I would just close the handle instead of leaking it in the error cases.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course, but in addition to that it's better to use a dedicated handle for IsWow64Process(), as it needs a specific permission which we use only one time.

is64Bit = result != 0;

pModule=getModuleAddr(modname ? modname : procname);
if (!pModule) {
dwPid = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaking hProcess?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'm going to move it above OpenProcess().

// The first 4 bytes constitute the magical number in ASCII: 0x7F 45 4c 46.

std::stringstream ss;
ss << std::string("/proc/");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why the std::string wrapping? Just causes a needless alloc. Pretty sure there's a const char* overload.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I took the code from getModuleAddr(), which was written by @mkrautz.

How would you do it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ss << "/proc/";

Should work I think.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tried, it works.

T peekProc(PTR_TYPE base) {
T v = 0;
if (!peekProc(base, reinterpret_cast<T *>(&v), sizeof(T))) {
procptr_t peekProcPtr(procptr_t base) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should document that this relies on initialize.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a new pull request, as this one is focused on the automatic pointer size, not on cleaning up.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency was introduced by making it rely in the 64bit check so imho documenting that belongs into the PR

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, every peekProc() function relies on initialize().

@davidebeatrici davidebeatrici force-pushed the plugins-automatic-architecture-detection branch 2 times, most recently from ad7f74e to ce1df33 Compare November 14, 2017 21:58
std::ifstream ifs;
ifs.open(ss.str(), std::ifstream::binary);
if (ifs.is_open()) {
ifs.read(elf, 5);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing check for failure. I guess in this case we could just not check and instead make sure elf is zero initialized. Bad habit to get into though.

char elf[5];

std::stringstream ss;
ss << std::string("/proc/");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ss << "/proc/";

std::stringstream ss;
ss << std::string("/proc/");
ss << static_cast<unsigned long>(pid);
ss << std::string("/exe");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same


BOOL isWow64Process;
if (!IsWow64Process(handle, &isWow64Process)) {
return -1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leaking handle

std::ifstream ifs;
ifs.open(ss.str(), std::ifstream::binary);
if (ifs.is_open()) {
ifs.read(elf, 5);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should sizeof elf. I believe we have a define for array sizeof somewhere.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@@ -23,7 +19,8 @@
#include "mumble_plugin.h"

pid_t pPid;
static PTR_TYPE_CONCRETE pModule;
int is64Bit;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Named like a bool. Should be a bool.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it should, but C doesn't have a boolean data type, as pointed out by @hacst.

static inline PTR_TYPE_CONCRETE getModuleAddr(DWORD pid, const wchar_t *modname) {
static inline int checkProcessIs64Bit(const DWORD pid)
{
// This function returns 0 if the process is 32-bit and 1 if it's 64-bit.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be a method comment!?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right.

Copy link
Contributor

@hacst hacst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from my minor comment LGTM. Please make sure to test on Windows and Linux but then I see no reason for you not to land it without another review iteration.

ifs.read(elf, LENGTH_OF(elf));
ifs.close();

if (ifs.gcount() != 5) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should also use the macro.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, right.

…cific headers and variables

This commit removes the architecture-specific headers, by keeping only the OS-specific ones.
The different headers were needed to keep the legacy Windows header, after we created the "procptr32_t" (4 bytes) and "procptr64_t" (8 bytes) variables.
We created these variables because the "peekProc" functions read as many bytes as the variable can hold. A pointer is 4 bytes on 32 bit platforms and 8 bytes on 64 bit ones.

Now there's a new variable, called "procptr_t" and with a size of 8 bytes (unsigned long long).
We had a "peekProc" template function which returned the value stored at the specified memory address, but it has been used only to read pointers so far.
Since we needed a new function that checks the process architecture and sets the correct size of the memory to read, I decided to "recycle" it.
This commit removes the legacy header, with the new one taking its name.
@davidebeatrici davidebeatrici force-pushed the plugins-automatic-architecture-detection branch from 0656e1f to 2a51c7b Compare November 19, 2017 20:49
@davidebeatrici davidebeatrici merged commit fba1d65 into mumble-voip:master Nov 19, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants