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

Race condition when creating initial user could allow multiple users to be created. #1834

Closed
baus opened this issue Jan 4, 2014 · 11 comments
Labels
bug [triage] something behaving unexpectedly

Comments

@baus
Copy link

baus commented Jan 4, 2014

In /core/server/models/user.js in the add() function the database is asynchronously queried for the number of users in the database, and if one exists, then the user cannot create a new user.

It is possible multiple for connections to query the database for the number of users before one is created. In that case, multiple users will be created.

@javorszky
Copy link
Contributor

Right, sooo... working on this thing.

Fix will include:

  • a progress bar of sorts
  • unattaching the handler from the submit button
  • making sure in the backend Ghost behaves correctly

@ErisDS
Copy link
Member

ErisDS commented Jan 4, 2014

We'll fix the UI issues with #1841.

For the backend I was thinking the best way to do this may be to use transactions?

@baus
Copy link
Author

baus commented Jan 5, 2014

I opened a second PR on this issue. My first one still had a race condition. This is more difficult to solve than it seems because it requires atomic operations at the database level -- specifically conditional inserts.

@baus
Copy link
Author

baus commented Jan 5, 2014

I just read @ErisDS comment on my previous PR and realized my new PR still doesn't meet the guidelines. I'll give this one more try. Third time's a charm.

@ErisDS
Copy link
Member

ErisDS commented Jan 5, 2014

You shouldn't need to open a new PR - with a little git foo the old one can be cleaned up 👍

@baus
Copy link
Author

baus commented Feb 4, 2014

I've been doing some work on this issue. I know this is an unlikely scenario, and will be resolved with multiple user support, but I do think there is value in developing procedures to deal with race conditions issues in the future.

I wrote a test which can reproduce the issue in my branch.

I haven't submitted a PR on this because I don't have a solution ready, but I have an idea on how I want to address it. Here are some of my notes

I looked into using Knex transactions, but they depend on limiting connections the database. As soon as there is more than one process accessing the database (which will be more common when load balancing is available in Node.js 0.12), then Knex transactions won't address the issue.

I would prefer to add a constraint into the database using CHECK. But this has a couple issues.

  1. schema.js doesn't support CHECK

  2. MySQL doesn't support CHECK

As the application gets more complex, I think it is going to be difficult to support multiple databases. Maybe there is another solution, but since Ghost requires a SQL database, I personally think the most straight forward solution is to push the problem down to the database.

@sebgie
Copy link
Contributor

sebgie commented Feb 4, 2014

I have spent some time today to look into this issue. You are absolutely right, that this issue will be irrelevant when multiple users are supported.

Since supporting multiple databases is important for Ghost and special SQL queries are hard to maintain, I think that the solution to this problem is adding a semaphore/mutex/lock and ensure it is treated as a critical section. Do you know any other functions that contain a similar problem?

@baus
Copy link
Author

baus commented Feb 4, 2014

Unfortunately, since it is event driven and single threaded, there really isn't a concept of a semaphore, mutex, or lock in Node. The best you can do is perform I/O synchronously in one thread, which will pause all connections until that I/O completes. I think the solution is to make writes to the user table atomic at the database level, but that is hard to do for multiple databases.

I believe race conditions occur at other places in the code, but I haven't look at them as carefully as this issue. I'm pretty sure a similar problem exists when creating numbered slugs for posts.

@baus
Copy link
Author

baus commented Feb 5, 2014

I hope this latest PR does the trick. I would had preferred to use the database to enforce the constraint, but that is difficult to do given the limitations on the database selection and schema creation. This strategy of using closures to maintain state does not work in load-balanced or multi-process environments, because it depends on the state within one process.

@ErisDS ErisDS mentioned this issue Jun 17, 2014
26 tasks
@ErisDS ErisDS added the bug label Jul 1, 2014
@ErisDS
Copy link
Member

ErisDS commented Jul 29, 2014

@sebgie I think the new approach to the initial owner should resolve this?

@sebgie
Copy link
Contributor

sebgie commented Jul 29, 2014

Yes, this race condition is not relevant due to support for multi user anymore.

@sebgie sebgie closed this as completed Jul 29, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug [triage] something behaving unexpectedly
Projects
None yet
Development

No branches or pull requests

4 participants