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

wallet: prevent the same wallet file from being opened by multiple processes #3994

Merged
merged 3 commits into from
Jun 28, 2018

Conversation

stoffu
Copy link
Contributor

@stoffu stoffu commented Jun 12, 2018

Maybe this way of trying to lock a file is stupid, but perhaps better than nothing...

@moneromooo-monero
Copy link
Collaborator

I had an idea of doing this via advisory locks, which are cleared when a process ends. I'm not sure it can be done cross platform though. If the wallet crashes or gets killed, this lock file doesn't go away. Maybe that's good enough though.

@hyc
Copy link
Collaborator

hyc commented Jun 20, 2018

Advisory locks would certainly be cleaner. We had locking code for the blockchain in monerod before, can just troll thru git history and paste that in here instead.

@stoffu
Copy link
Contributor Author

stoffu commented Jun 21, 2018

@moneromooo-monero @hyc
Thanks a lot for your suggestion, I've updated the patch accordingly.

I'm quite unfamiliar with Windows/Linux APIs so I might be using them inappropriately, but it seems to be working as far as I tested with Mac, Ubuntu and Windows.


m_keys_file_locker.reset();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I realized this temporary unlocking was necessary due to Windows (otherwise the file couldn't be loaded).

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe add a comment saying so ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok

{
#ifdef WIN32
m_fd = INVALID_HANDLE_VALUE;
WCHAR wide_path[1000];
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there no PATH_MAX for Windows ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was copied from code added in #3313. It seems like Windows also has _PATH_MAX, but the value might change depending on different versions of Windows, and it doesn't seem like the universal way of guaranteeing sufficient length for path names. The current codebase has two places where MultiByteToWideChar is used:

static int utf8_to_utf16(const char *src, int srcsize, wchar_t **dst, int *dstsize)
{
int need;
wchar_t *result;
need = MultiByteToWideChar(CP_UTF8, 0, src, srcsize, NULL, 0);
if (need == 0xFFFD)
return EILSEQ;
if (need == 0)
return EINVAL;
result = malloc(sizeof(wchar_t) * need);
if (!result)
return ENOMEM;
MultiByteToWideChar(CP_UTF8, 0, src, srcsize, result, need);
if (dstsize)
*dstsize = need;
*dst = result;
return 0;
}

LPCWSTR String::AnsiToUtf16(const char* ansi) {
if (!ansi) return NULL;
const int length = strlen(ansi);
const int unicode_length =
MultiByteToWideChar(CP_ACP, 0, ansi, length,
NULL, 0);
WCHAR* unicode = new WCHAR[unicode_length + 1];
MultiByteToWideChar(CP_ACP, 0, ansi, length,
unicode, unicode_length);
unicode[unicode_length] = 0;
return unicode;
}

In both cases, the length of the resulting UTF-16 string is obtained by first calling the function with the output location set to NULL, which seems like the right way.

If this way is to be used, I think it makes sense to also replace the corresponding code in file_io_utils. What do you think? CC: @rbrunner7 @hyc

Copy link
Contributor

@rbrunner7 rbrunner7 Jun 24, 2018

Choose a reason for hiding this comment

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

Guilty ... I knew that, but when I wrote that code for #3313 I was on my last legs after working so long on that UTF-8 filename stuff that I simply hacked it in the simplest possible way.

I agree that it should be replaced sooner or later.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agreed, that's the safe way to do it.

{
if (flock(m_fd, LOCK_EX | LOCK_NB) == -1)
{
close(m_fd);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This could do with a MERROR/MWARNING so weird stuff afterwards can be known to be coming from that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok

std::string buf;
r = ::serialization::dump_binary(keys_file_data, buf);
r = r && epee::file_io_utils::save_string_to_file(keys_file_name, buf); //and never touch wallet_keys_file again, only read
CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet keys file " << keys_file_name);
m_keys_file_locker.reset(new tools::file_locker(m_keys_file.c_str()));
Copy link
Collaborator

Choose a reason for hiding this comment

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

This uses c_str, but the ctor uses std::string, so this creates a new temporary string for no reason.
Having the ctor use const char * seems the way to support both without temp object creation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok


m_keys_file_locker.reset();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe add a comment saying so ?

{
if (flock(m_fd, LOCK_EX | LOCK_NB) == -1)
{
MERROR("Failed to lock " << filename);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could we get errno please ? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok

@stoffu stoffu force-pushed the lock-keys-file branch 5 times, most recently from 07f5b68 to 4686fc4 Compare June 25, 2018 04:27
@stoffu
Copy link
Contributor Author

stoffu commented Jun 25, 2018

Code updated reflecting suggestions

@luigi1111 luigi1111 merged commit 3d623a8 into monero-project:master Jun 28, 2018
luigi1111 added a commit that referenced this pull request Jun 28, 2018
1d17647 epee.string_tools: add conversion between UTF-8 and UTF-16 (stoffu)
59de6f8 util: add file_locker class (stoffu)
3d623a8 wallet: prevent the same wallet file from being opened by multiple processes (stoffu)
stoffu added a commit to stoffu/monero that referenced this pull request Jun 28, 2018
luigi1111 added a commit that referenced this pull request Jun 28, 2018
49dc78d util: fix mistakes made in #3994 (stoffu)
stoffu added a commit to stoffu/monero that referenced this pull request Nov 6, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants