-
-
Notifications
You must be signed in to change notification settings - Fork 824
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
Fix bug where a % in a serialized array can lead to the data being broken #16694
Conversation
(Standard links)
|
5f35fd0
to
9a45f3b
Compare
@eileenmcnaughton I've traced this a bit and I think this is what's going on: The query in CRM_Core_DAO::executeQuery("INSERT INTO civicrm_prevnext_cache (entity_table, entity_id1, entity_id2, cacheKey, data) VALUES
(%1, %2, %3, %4, '{$data}')", [
1 => [$entity_table, 'String'],
2 => [$entity_id1, 'Integer'],
3 => [$entity_id2, 'Integer'],
4 => [$cacheKey, 'String'],
]); Note that the first 4 parameters use placeholders with escaping, while Not sure if there's a workaround for this or if we want to change the contract so that I suppose we could add a |
9a45f3b
to
3cb0d57
Compare
I've added a commit that fixes this based on digging by @pfigel into what the problem is. Commit comments : Fix bug where a % in a serialized array can lead to the data being broken It turns out that is a field in a serialized array has a %2 (for example) this gets swapped in executeQuery for the Some thoughts
|
@eileenmcnaughton I don't fully understand why handling serialized values differently is necessary. I might be missing something, but for all intents and purposes, a serialized array should just be a string, so this should work: CRM_Core_DAO::executeQuery("INSERT INTO civicrm_prevnext_cache (entity_table, entity_id1, entity_id2, cacheKey, data) VALUES
('civicrm_contact', %1, %2, %3, %4)", [
1 => [$dstID, 'Integer'],
2 => [$srcID, 'Integer'],
3 => [$cacheKeyString, 'String'],
4 => [serialize($row), 'String'],
]
); For |
@pfigel the problem is that if the seralized content contains a %1 or %2 etc Execute Query would then add in the value of either the dstId or srcID etc |
@pfigel what you suggest would work I think - but generally where we have added serrialize handling for arrays we've taken into account the various 'serialize' types we have |
tests/phpunit/api/v3/JobTest.php
Outdated
$this->individualCreate(['first_name' => 'Gerrit%0a%2e%0a']); | ||
$this->callAPISuccess('Job', 'process_batch_merge', []); | ||
// As serialized | ||
//a:6:{s:5:"dstID";s:1:"4";s:7:"dstName";s:23:"Mr. Anthony Anderson II";s:5:"srcID";s:1:"5";s:7:"srcName";s:31:"Mr. Gerrit%0a4e%0a Anderson II";s:6:"weight";s:2:"10";s:8:"canMerge";b:1;} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should these get uncommented out?
I think this is a problem specific to the current implementation, where
I have some reservations on doing this in |
@pfigel so I can generally accept that - where it would break down is if $row has any legitimate slashes in it as they would be escaped AFTER serialization |
I think that's fine? Escaping the value is a way to encode the value so MySQL understands it. Take this example: $x = serialize(['first_name' => 'foo\\bar\'baz']);
When we run that through Basically: any interaction with MySQL should always look like this (in really weird pseudo-code): SELECT .... WHERE x = escape(something(somethingelse(value))) and generally never: SELECT .... WHERE x = something(escape(somethingelse(value))) |
3cb0d57
to
2f5102a
Compare
@pfigel @seamuslee001 I added @pfigel's example to the test with @pfigel's suggestions - test passes so I think it's right |
2f5102a
to
46710fd
Compare
…oken It turns out that is a field in a serialized array has a %2 (for example) this gets swapped in executeQuery for the %2 value (in this case srcID - rendering the serialized array invalid. This proposes that we explicitly handle arrays as a data type in compose query. Some thoughts 1) we could make serialized arrays valid types in validate (not done here) 2) we could iterate through the array keys & values escaping them - at this stage it's left in the calling function 3) there are whole bikeshed factories to keep in business on discussion of whether 'Array-1', 'Array-2' etc are the right format
46710fd
to
2e09a60
Compare
This looks good to me and its passing tests so lets merge this in |
Overview
Fixes obscure dedupe bug
Before
Dedupe will fail on a contact with '%2' in their name
After
Dedupe can cope
Technical Details
Basically we have a contact in our DB who had a weird string (carriage returns & a .) in his name.
The dedupe script fell over on him because it could not unserialize what it had serialised for
his display name.
It turns out that is a field in a serialized array has a %2 (for example) this gets swapped in executeQuery for the
%2 value (in this case srcID - rendering the serialized array invalid. This proposes that we
explicitly handle arrays as a data type in compose query.
Some thoughts
we could make serialized arrays valid types in validate (not done here)
we could iterate through the array keys & values escaping them -
at this stage it's left in the calling function
there are whole bikeshed factories to keep in business on discussion of whether
'Array-1', 'Array-2' etc are the right format
---- notes below written before @pfigel pointed to where it was going awol-----
It then retrieves with this query
And the value in data is
which fails to unserialize here
civicrm-core/CRM/Core/BAO/PrevNextCache.php
Line 288 in bd4c91f
Comments
@pfigel @ejegg @seamuslee001 if anyone has thoughts - this IS pretty obscure & I'm comfortable it's not a security hole