1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-31 08:58:20 +01:00

Enforce that global locks have keys shorter than 64 characters

Summary:
Fixes T7484. There's a bunch of spooky mystery here but the current behavior can probably cause problems in at least some situations.

Also moves a couple callsigns to monograms (see T4245).

Test Plan:
  - Faked a short lock length to hit the exception.
  - Updated normally.
  - Grepped for other use sites, none seemed suspicious or likely to overflow the lock length.

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T7484

Differential Revision: https://secure.phabricator.com/D12263
This commit is contained in:
epriestley 2015-04-02 13:42:22 -07:00
parent c39b64d963
commit 2b3d3cf7e4
4 changed files with 65 additions and 6 deletions

View file

@ -5235,6 +5235,7 @@ phutil_register_library_map(array(
'PhabricatorHandleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorHarbormasterApplication' => 'PhabricatorApplication',
'PhabricatorHarbormasterConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorHash' => 'Phobject',
'PhabricatorHashTestCase' => 'PhabricatorTestCase',
'PhabricatorHelpApplication' => 'PhabricatorApplication',
'PhabricatorHelpController' => 'PhabricatorController',

View file

@ -51,10 +51,9 @@ final class PhabricatorRepositoryManagementUpdateWorkflow
}
$repository = head($repos);
$callsign = $repository->getCallsign();
try {
$lock_name = get_class($this).':'.$callsign;
$lock_name = 'repository.update:'.$repository->getID();
$lock = PhabricatorGlobalLock::newLock($lock_name);
$lock->lock();
@ -135,7 +134,7 @@ final class PhabricatorRepositoryManagementUpdateWorkflow
$proxy = new PhutilProxyException(
pht(
'Error while pushing "%s" repository to mirrors.',
$repository->getCallsign()),
$repository->getMonogram()),
$ex);
phlog($proxy);
}

View file

@ -39,7 +39,20 @@ final class PhabricatorGlobalLock extends PhutilLock {
public static function newLock($name) {
$namespace = PhabricatorLiskDAO::getStorageNamespace();
$full_name = 'global:'.$namespace.':'.$name;
$namespace = PhabricatorHash::digestToLength($namespace, 20);
$full_name = $namespace.'-g:'.$name;
$length_limit = 64;
if (strlen($full_name) > $length_limit) {
throw new Exception(
pht(
'Lock name "%s" is too long (full lock name is "%s"). The '.
'full lock name must not be longer than %s bytes.',
$name,
$full_name,
new PhutilNumber($length_limit)));
}
$lock = self::getLock($full_name);
if (!$lock) {

View file

@ -1,7 +1,8 @@
<?php
final class PhabricatorHash {
final class PhabricatorHash extends Phobject {
const INDEX_DIGEST_LENGTH = 12;
/**
* Digest a string for general use, including use which relates to security.
@ -68,11 +69,56 @@ final class PhabricatorHash {
}
$result = '';
for ($ii = 0; $ii < 12; $ii++) {
for ($ii = 0; $ii < self::INDEX_DIGEST_LENGTH; $ii++) {
$result .= $map[(ord($hash[$ii]) & 0x3F)];
}
return $result;
}
/**
* Shorten a string to a maximum byte length in a collision-resistant way
* while retaining some degree of human-readability.
*
* This function converts an input string into a prefix plus a hash. For
* example, a very long string beginning with "crabapplepie..." might be
* digested to something like "crabapp-N1wM1Nz3U84k".
*
* This allows the maximum length of identifiers to be fixed while
* maintaining a high degree of collision resistance and a moderate degree
* of human readability.
*
* @param string The string to shorten.
* @param int Maximum length of the result.
* @return string String shortened in a collision-resistant way.
*/
public static function digestToLength($string, $length) {
// We need at least two more characters than the hash length to fit in a
// a 1-character prefix and a separator.
$min_length = self::INDEX_DIGEST_LENGTH + 2;
if ($length < $min_length) {
throw new Exception(
pht(
'Length parameter in digestToLength() must be at least %s, '.
'but %s was provided.',
new PhutilNumber($min_length),
new PhutilNumber($length)));
}
// We could conceivably return the string unmodified if it's shorter than
// the specified length. Instead, always hash it. This makes the output of
// the method more recognizable and consistent (no surprising new behavior
// once you hit a string longer than `$length`) and prevents an attacker
// who can control the inputs from intentionally using the hashed form
// of a string to cause a collision.
$hash = PhabricatorHash::digestForIndex($string);
$prefix = substr($string, 0, ($length - ($min_length - 1)));
return $prefix.'-'.$hash;
}
}