Skip Menu |

This queue is for tickets about the DBIx-Class CPAN distribution.

Report information
The Basics
Id: 130144
Status: open
Priority: 0/
Queue: DBIx-Class

People
Owner: Nobody in particular
Requestors: ether [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: 0.082841
Fixed in: (no value)



Subject: _inflated_column cache leaking, not updated/cleared at the right time
I encountered a bug in DBIx::Class::PassphraseColumn, which, while fixing, I found some issues with the core inflation/updating code: The branch I have been working in, which contains my workarounds, is https://github.com/karenetheridge/DBIx-Class-PassphraseColumn/tree/ether/failing-set-inflated-column-override First, I found that DBIx::Class::InflateColumn::set_inflated_column is setting/clearing $self->{_inflated_column}{$col} *after* calling set_column, rather than before -- this is a problem as DBICPPC's overridden set_column needs to know whether the original value passed to $row->$col (or $row->update) was an inflated object or not (if it started off inflated, then the resulting deflated string is already an encrypted passphrase; if not, then it is a raw passphrase that needs to be encoded before being stored). I do not know if this ordering is intentional or if anything else will be broken by switching it, but the switch is exactly what I need here. Second, I found that DBIx::Class::Row::set_inflated_columns is failing to *clear* old _inflated_column caches in the case that the new value is not a reference. Therefore, old values will leak through when first the value is inflated, and then later it is updated to a deflated value.
More background, which might be useful: 14:08 * ether finds another bug in DBIx::Class::PassphraseColumn where I'm incredulous that I'm the first to find it 14:08 < ether> $row->update({ password => Authen::Passphrase::AcceptAll }) doesn't DTRT 14:08 < ether> er s/All/All->new/ 14:09 < ether> the literal AcceptAll passphrase, in crypt form, is '' 14:09 < ether> so you'd expect '' to be stored into the db 14:09 < ether> and then when it's inflated by BlowfishCrypt or whatever, everything checks against it 14:09 < ether> but instead, '' is encrypted through blowfish and *that* is stored 14:09 < ether> so you've just fucked your password entry 14:10 < ether> the problem is that DBIx::Class::PassphraseColumn is only overriding set_column, which is called *after* the deflation has happened 14:10 < ether> and it then dutifully encrypts that string and stores it 14:10 < ether> rather than realizing oh hey, this already passed through an AP object, I've already got the literal string to store, we're done 14:10 < ether> so I have to override set_inflated_column as well, It hink 14:11 < ether> I haven't worked out quite yet how to fix this 14:11 < ether> the funny thing is that this scenario *is in the fucking synopsis* 14:11 < ether> and it never worked 14:12 < ether> I've got repro test cases here -- https://github.com/karenetheridge/DBIx-Class-PassphraseColumn/commit/0f69aacd67ad07deb6f6c60532157e7ffeccfeaa 14:17 < ether> I think I see a fix. I will post it here if it seems weird, or just push it out as another -TRIAL if I think it's obvious enough that I haven't fucked it up 15:54 < ether> ..and another bug found in core DBIx::Class. 15:55 < ether> it is leaking old data in $row->{_inflated_column}{$col} that should have been cleared 16:04 < ether> I've got a fix here, also patching around the buggy DBIx::Class::Row::set_inflated_columns, here -- https://github.com/karenetheridge/DBIx-Class-PassphraseColumn/tree/ether/failing-set-inflated-column-override 16:04 < ether> now I have to write this up as an RT for ribasushi to reject 16:16 < ether> filed as https://rt.cpan.org/Ticket/Display.html?id=130144 16:24 < ilmari> is passing a deflated value to set_inflated_column supposed to dtrt? 16:27 < ether> I believe so 16:28 < ether> it has a is_literal_value check at the top of it, where it just calls set_column and clears its cache 16:28 < ether> but this sub isn't called if the value isn't even a reference 16:29 < ether> so if you do $row->update({ foo => 1 }) it won't get called, but it will for $row->update({ foo => \[ 'something funky for SQLA to handle' ] }) 16:30 < ether> so, old values leak when you do $foo->update({ foo => $obj }); $row->update({foo => 1 }); $row->update({ foo => $anotherobj }); 16:30 < ether> before that third update, the original object is still hanging around in $row->{_inflated_column}{foo} 16:31 < ether> I can fix my DBIx::Class::PassphraseColumn usecase if 1. that cache is properly cleared when there is no longer an inflated object in play, and 2. it is updated/cleared *before* calling set_column, rather than after 16:32 < ether> #1 seems like an obvious fix; #2 I'm not sure about as something somewhere may be depending on the order the way it was
On Tue Jul 23 01:15:55 2019, ETHER wrote: Show quoted text
> First, I found that DBIx::Class::InflateColumn::set_inflated_column is > setting/clearing $self->{_inflated_column}{$col} *after* calling > set_column, rather than before -- this is a problem as DBICPPC's > overridden set_column needs to know whether the original value passed > to $row->$col (or $row->update) was an inflated object or not (if it > started off inflated, then the resulting deflated string is already an > encrypted passphrase; if not, then it is a raw passphrase that needs > to be encoded before being stored). I do not know if this ordering is > intentional or if anything else will be broken by switching it, but > the switch is exactly what I need here.
There is an extensive test suite. Make the change, see what breaks. Show quoted text
> Second, I found that DBIx::Class::Row::set_inflated_columns is failing > to *clear* old _inflated_column caches in the case that the new value > is not a reference. Therefore, old values will leak through when > first the value is inflated, and then later it is updated to a > deflated value.
This seems to be a duplicate of https://rt.cpan.org/Ticket/Display.html?id=125067#txn-1781343 As noted there: not yet.
On 2019-07-23 01:26:25, RIBASUSHI wrote: Show quoted text
> > ...I do not know if this ordering is > > intentional or if anything else will be broken by switching it, but > > the switch is exactly what I need here.
> > There is an extensive test suite. Make the change, see what breaks.
I did, and there is one failure, but it does not seem to make sense with the change made, so I am unable to determine what else needs to be fixed as a consequence.