Obtain an exclusive lock before writing to the database

This prevents race conditions caused by multiple instances of TinyIB
accessing the database simultaneously.

Resolves #251.
This commit is contained in:
Trevor Slocum 2022-04-08 14:55:02 -07:00
parent 93c91aec20
commit 57b50658a2
3 changed files with 22 additions and 0 deletions

View File

@ -257,6 +257,8 @@ if (!$loggedin) {
$redirect = true; $redirect = true;
// Check if the request is to make a post // Check if the request is to make a post
if (!isset($_GET['delete']) && !isset($_GET['manage']) && (isset($_POST['name']) || isset($_POST['email']) || isset($_POST['subject']) || isset($_POST['message']) || isset($_POST['file']) || isset($_POST['embed']) || isset($_POST['password']))) { if (!isset($_GET['delete']) && !isset($_GET['manage']) && (isset($_POST['name']) || isset($_POST['email']) || isset($_POST['subject']) || isset($_POST['message']) || isset($_POST['file']) || isset($_POST['embed']) || isset($_POST['password']))) {
$lock = lockDatabase();
if (TINYIB_DBMIGRATE) { if (TINYIB_DBMIGRATE) {
fancyDie(__('Posting is currently disabled.<br>Please try again in a few moments.')); fancyDie(__('Posting is currently disabled.<br>Please try again in a few moments.'));
} }
@ -600,6 +602,8 @@ if (!isset($_GET['delete']) && !isset($_GET['manage']) && (isset($_POST['name'])
die(); die();
// Check if the request is to report a post // Check if the request is to report a post
} elseif (isset($_GET['report']) && !isset($_GET['manage'])) { } elseif (isset($_GET['report']) && !isset($_GET['manage'])) {
$lock = lockDatabase();
if (!TINYIB_REPORT) { if (!TINYIB_REPORT) {
fancyDie(__('Reporting is disabled.')); fancyDie(__('Reporting is disabled.'));
} }
@ -681,6 +685,8 @@ EOF;
fancyDie(__('Post reported.'), $go_back); fancyDie(__('Post reported.'), $go_back);
// Check if the request is to delete a post and/or its associated image // Check if the request is to delete a post and/or its associated image
} elseif (isset($_GET['delete']) && !isset($_GET['manage'])) { } elseif (isset($_GET['delete']) && !isset($_GET['manage'])) {
$lock = lockDatabase();
if (!isset($_POST['delete'])) { if (!isset($_POST['delete'])) {
fancyDie(__('Tick the box next to a post and click "Delete" to delete it.')); fancyDie(__('Tick the box next to a post and click "Delete" to delete it.'));
} }
@ -721,6 +727,8 @@ EOF;
$redirect = false; $redirect = false;
// Check if the request is to access the management area // Check if the request is to access the management area
} elseif (isset($_GET['manage'])) { } elseif (isset($_GET['manage'])) {
$lock = lockDatabase();
$text = ''; $text = '';
$onload = ''; $onload = '';
$navbar = '&nbsp;'; $navbar = '&nbsp;';

View File

@ -6,6 +6,7 @@ if (!defined('TINYIB_BOARD')) {
define('TINYIB_NEWTHREAD', '0'); define('TINYIB_NEWTHREAD', '0');
define('TINYIB_INDEXPAGE', false); define('TINYIB_INDEXPAGE', false);
define('TINYIB_RESPAGE', true); define('TINYIB_RESPAGE', true);
define('TINYIB_LOCKFILE', 'tinyib.lock');
define('TINYIB_WORDBREAK_IDENTIFIER', '@!@TINYIB_WORDBREAK@!@'); define('TINYIB_WORDBREAK_IDENTIFIER', '@!@TINYIB_WORDBREAK@!@');
// Account roles // Account roles

View File

@ -11,6 +11,19 @@ if (!function_exists('array_column')) {
} }
} }
// lockDatabase obtains an exclusive lock to prevent race conditions when
// accessing the database.
function lockDatabase() {
if (TINYIB_LOCKFILE == '') {
return true;
}
$fp = fopen(TINYIB_LOCKFILE, 'c+');
if (!flock($fp, LOCK_EX)) {
fancyDie('Failed to lock control file.');
}
return $fp;
}
function hashData($data, $force = false) { function hashData($data, $force = false) {
global $bcrypt_salt; global $bcrypt_salt;
if (substr($data, 0, 4) == '$2y$' && !$force) { if (substr($data, 0, 4) == '$2y$' && !$force) {