I'm not sure if this is a bug or by design (but it's certainly causing some discussion over in this issue with organic groups: http://drupal.org/node/1182338).
The issue comes when a user attempts to download a file stored by a field, using the private file system:
- file_file_download() runs, which figures out which field the file belongs to;
- it then calls field_access() on the field to see if the user has access to that field;
- field_access() invokes the hook_field_access() hooks.
However, the value of $field passed to the various hook_field_access() implementations does not include a 'field_name' which one would expect. Here's an example:
Array
(
[fid] => 12
[display] => 1
[description] =>
[uid] => 7
[filename] => sample.pdf
[uri] => private://sample.pdf
[filemime] => application/pdf
[filesize] => 208268
[status] => 1
[timestamp] => 1312296292
[type] => application
)
Comment | File | Size | Author |
---|---|---|---|
#96 | i-messed-up-1245220-96.patch | 922 bytes | Berdir |
#91 | file-cleanup-1245220-91.patch | 2.34 KB | David_Rothstein |
#87 | file-cleanup-1245220-87.patch | 1.49 KB | David_Rothstein |
#83 | 1245220-83.patch | 11.03 KB | corvus_ch |
#79 | file-file-download-context-1245220-79.patch | 11.08 KB | Berdir |
Comments
Comment #1
Damien Tournoud CreditAttribution: Damien Tournoud commentedEw. This is bad :)
Confirmed, the part of the code of file_file_download() that handles field-level permission is just totally bogus.
Comment #2
amitaibuSubscribe
Comment #3
spacereactor CreditAttribution: spacereactor commentedSubscribe
Comment #4
dpolant CreditAttribution: dpolant commentedCan some one test this patch I came up with for this issue?
http://drupal.org/node/1182338#comment-4868078
Comment #5
Anonymous (not verified) CreditAttribution: Anonymous commentedsubscribe.
Comment #6
dpolant CreditAttribution: dpolant commentedHere is the patch. It applies cleanly to 7.7 and 7.x-dev.
Comment #7
dpolant CreditAttribution: dpolant commentedHere is a slightly better version that could prevent a null from being passed to hook_field_access.
Comment #8
catchSeem like when we originally assign $field, that could just use $field = field_info_field($field_name) rather than assigning it twice?
It looks like the function could be cleaned up a bit otherwise too, but not sure if we should do that here or open up another issue.
Comment #9
bochen87 CreditAttribution: bochen87 commentedworks fine!
Comment #10
catchNeeds work per #8.
Comment #11
bfroehle CreditAttribution: bfroehle commentedThis should be what catch was suggesting in #8.
Comment #12
bfroehle CreditAttribution: bfroehle commented~
Comment #13
othermachines CreditAttribution: othermachines commented#11 works for me.
Comment #14
shotokai CreditAttribution: shotokai commented#11 works for me
Comment #15
CarbonPig CreditAttribution: CarbonPig commented#11 works for me to fix issue described here: http://drupal.org/node/1182338 - where, private file fields were not viewable by other organic group members.
Thanks!
Comment #16
seddonym CreditAttribution: seddonym commentedI notice the major version number has been changed. What's the process here, does that mean that it won't be fixed in Drupal 7? Sorry if this is a naive question.
Comment #17
bluestarstudios CreditAttribution: bluestarstudios commentedI'm sure it will be fixed. I've noticed that the general procedure is to first fix the issue for Drupal 8 and then backport to D7. So now the question is how is that Backport going? Does anybody have a patch for Drupal 7? Thanks!
Comment #18
bluestarstudios CreditAttribution: bluestarstudios commentedPatch #11 is for Drupal 8. Is there a version for Drupal 7.8? Thanks
Comment #19
webchickLet's get a test for this.
Comment #20
bluestarstudios CreditAttribution: bluestarstudios commentedThe #11 seems to cause the following error in Drupal 7.9.
EntityMalformedException: Missing bundle property on entity of type node. in entity_extract_ids() (line 7405 of /home4/bawiecco/public_html/drupal-7.9/includes/common.inc).
It worked fine in 7.8, but some changes in the new version are causing this error.
Comment #21
bluestarstudios CreditAttribution: bluestarstudios commentedAfter Entity API, Views and cTools (among others) got updated errors have disappeared and patch applies correctly again.
Lets get this one tested out. :)
Comment #22
Weaver CreditAttribution: Weaver commentedEnded up here from: http://drupal.org/node/1182338
Path #11 solved the issue for me in Drupal 7.9
Comment #24
BarisW CreditAttribution: BarisW commentedSame here, in Drupal 7.10. Can we backport this to Drupal 7 as well?
The patch in #11 solved the problem for me.
Comment #25
plachHere is a rerolled patch with a test-only version to show that the bug is actually captured. It applies just fine to D7 with -p2.
Comment #26
plachComment #27
plachThe patches in #25 are not getting tested, uploading them again.
Comment #28
plachStill postponed :(
Comment #29
plachTrying to post the patches separately.
Comment #30
xjmRe-uploading the patches will not help, unfortunately. 8.x tests failed to run earlier. I'll requeue the last patch if needed, but there is a backlog at the moment (and the more patches we add, the bigger the backlog). :)
Comment #31
plach@xjm:
When I first uploaded the patches the queue was empty, thus I thinked about a problem while forwarding them to the testbot. I did not spot the HEAD was failing, sorry.
Anyway, the test results are ok, so if the test looks good this should be RTBC. Code reviews welcome :)
Comment #32
xjmYep, this looks RTBC to me. Sneaking in a docs fix here--I clarified the inline comment and fixed a grammatical error. No commit credit please.
Comment #33
xjmThe interdiff I meant to attach in #32 in place of that second copy of the patch. Sorry testbot. ;)
Comment #34
catchCommitted/pushed to 8.x. Moving back to 7.x for backport.
Comment #35
catchNearly.
Comment #36
plachJust applied #32 with -p2 and rerolled. Back to RTBC.
Comment #37
David_Rothstein CreditAttribution: David_Rothstein commentedSo... I unpublished this issue for a while, because the security team was already in the process of working on a fix for the same problem in Drupal 7. (It turns out that under some circumstances, this bug led to security issues.) I didn't notice there was an issue here for it also until after it had been committed to Drupal 8.
Now that the fix is in Drupal 7 (http://drupal.org/node/1425084), there is some work to do for Drupal 8:
Although I don't think there's a security issue in Drupal 8 anymore, the above tasks probably add up to critical on their own, so I'm marking this issue as such.
For reference, I'm attaching a copy of the patch that was already committed to Drupal 7.
Comment #38
swentel CreditAttribution: swentel commentedHmm, I was bitten by the confusion when porting the issues in #1425330: Apply Aggregator and OpenID fixes from DRUPAL-SA-CORE-2012-001
Comment #39
scor CreditAttribution: scor commentedtagging Security Advisory follow-up
Comment #40
BerdirThere is another issue to be dealt with here:
- drupal_alter() now only accepts exactly 3 arguments, we have 4 which means that the alter hook actually never receives the fourth argument and any attempt in implementing that hook as he is documented will fail with errors.
The only way out there is to convert $entity_type and $entity into a single $context array with the two variables as array values.
Comment #41
WorldFallz CreditAttribution: WorldFallz commented@berdir -- yep, and I found this independently and created #1143460: hook_file_download_access_alter missing entity argument.
There's also #1462538: Change drupal_alter() to use only one context variable --- which makes sense as well.
I'm not sure if it's better to work here or in one of the other issues. either way we should pick one place and redirect the other issues to the correct location.
Comment #42
WorldFallz CreditAttribution: WorldFallz commentedi can't get d8 to install atm to test it out, but I'm thinking something like the attached.
Comment #43
tim.plunkettTagging.
Comment #44
WorldFallz CreditAttribution: WorldFallz commentedSince this is where the history and activity is, reposting dave reid's patch here (and marked the other issue as a dupe).
Comment #45
BerdirMerged the patches from #44 and #37 and went a step further. I merged all additional things into a single $context variable (entity, entity_type, field_info, field_item) for both hooks.
The advantage is that the both are almost equal now (except the $grants argument in the alter hook, obviously).
It's a bigger change this way, though.
Comment #47
BerdirLet's try that again.
Comment #49
BerdirAnother one that I missed.
Comment #51
BerdirI'm not able to implement my own hook ;).
Comment #53
BerdirOk, this one should now be green. Sorry for spaming the issue.
Comment #54
Berdir#53: single_context5.patch queued for re-testing.
Feedback. Anyone? ;)
Comment #56
BerdirRe-rolled.
Comment #57
aspilicious CreditAttribution: aspilicious commentedI read the comments, looked at the tests and the approach. Looks fine to me. Marking this rtbc.
Comment #58
catchPatch generally looks fine, but a couple of questions:
- I'm assuming we don't need the $entity_type parameter once all entities are classed objects, that's very close with only files left, so could we even remove it now?
- while drupal_alter() takes two $context arguments, that's a heavily loaded term in Drupal, would be good to think of another parameter name if possible (although no single word springs to mind to include entities, fields and field items). Also if we remove the $entity_type then can we actually skip the $context change in general?
Comment #59
aspilicious CreditAttribution: aspilicious commentedWe can't remove it now because the file entity isn't converted yet which is blocked on the other file issue that doesn't get proper reviews for unknown reasons.
/me is raising pressure :p
Comment #60
BerdirYes, the removal of entity_type wold make this unnecessary. What would you suggest then, postponing until the the file conversion patch is in? EDIT: Actually, to include the field *and* field item, we'd still need $context.
However, we'd still need to do something about 7.x. The only fix that would not break backwards compatibility would be doing a manual $function() call with the given arguments instead of using drupal_alter(). I can't think of anything else.
Comment #61
David_Rothstein CreditAttribution: David_Rothstein commentedThis "field item" terminology looks like a bit of a regression compared to what was committed in the D7 security patch. I think we should use something more like "file item" as was done there (to make it easier to understand the difference between the two variables); e.g., where we had:
To be honest I'm not sure how much it matters, but for consistency we should probably include it in D8 too.
Not sure I understand this comment... Besides possibly backporting the D8 test, what is left to change in D7, given that the security fix already went out?
Comment #62
WorldFallz CreditAttribution: WorldFallz commentedafaik, d7 is still broken as described by berdir above. And since the argument that's never passed is the $entity itself, besides the errors, it really hampers doing any kind of entity based access control for files.
Comment #63
catchIf we pass the $entity, then isn't the $field_item included as part of that anyway?
Comment #64
Berdir@catch It is included, but you don't know which one it is, if the entity has multiple items for the given field.
Changing to file item would be fine with me, I thought that field item was a common term for this. The problem that I'm seeing with file item is it's a new term (and not the same thing as file object/entity as it is an array and not a full file entity. there is, e.g., no uri)
Comment #65
catchI prefer 'field item' here, since that's actually what it is.
Makes sense with field item not knowing which one it is, that's annoying but don't see a way around it.
In that case it feels like the only remaining thing is to figure out whether we need this in 8.x:
Comment #66
David_Rothstein CreditAttribution: David_Rothstein commentedIf we keep "field item", let's at least improve the documentation to make clear what it is; after all, confusion between $field and $field_item is pretty much the entire source of this bug.
On the security.drupal.org discussion, @dww argued (pretty convincingly I think) that "field item" was confusing here because what you receive in this variable has nothing to do with the field it came from at all; the information is limited to the file itself. Which is how we wound up with the description I quoted above for D7 currently (which makes clear this is an array of information about the file, not an array of information about the field).
Thanks, sorry I missed that above. Maybe after this issue is fixed in D8 it would be a good idea to reopen #1143460: hook_file_download_access_alter missing entity argument for D7 and deal with that separately there? (I'm almost wondering if simply adding a $context3 parameter to drupal_alter() isn't the best way to solve this in D7.)
Comment #67
BerdirA field consists of field items which contain whatever is defined in the field schema (and attached during load etc.). That is IMHO standard terminology, see for example http://api.drupal.org/api/drupal/modules%21field%21field.module/function....
file item indicates that it is a file object, which it is *not*.
so, maybe "file field item"? ;)
Comment #68
WorldFallz CreditAttribution: WorldFallz commentedThat's actually what I'm recommending/doing with one of my contributed modules until this is fixed-- it's a tiny change and doesn't break any api's that way changing it just about any other way would. I just didn't think that was an acceptable option for a core bug fix.
Comment #69
effulgentsia CreditAttribution: effulgentsia commentedOnly drupal_alter() has a limited number of parameters, so there's no reason to use $context in hook_file_download_access(). This patch adjusts accordingly.
$context is consistent with other usage of drupal_alter(), especially entity/field related groupings, as in hook_field_attach_view_alter(). If given the other "context" work happening in D8, we want to change the argument name for this kind of usage, let's do so in a separate issue that covers all drupal_alter()s. That should not hold this issue up though.
Comment #70
BerdirMy reasoning for using the same $context argument to both hooks was to make them similar but I agree that it's not necessary.
Comment #71
aspilicious CreditAttribution: aspilicious commentedSo why isn't this rtbc yet? It's a critical with a working patch.
Comment #72
David_Rothstein CreditAttribution: David_Rothstein commentedempty($field_item)
check (see #61). In most cases it shouldn't matter, but we don't know what kinds of changes people are making to the entity in hook_entity_load()... and if a NULL field items slipped through to the hook, that wouldn't be good.However, it occurred to me, why don't we just make our lives simpler in Drupal 8 and pass $file (i.e. the actual file entity) in to the hook, rather than this bizarre array-that-is-similar-to-a-file-entity-but-isn't? Then we don't have to worry about what to call it, or how to document it. Plus, it would make a lot more sense for the hooks to receive this.
Is there a reason I'm not seeing why we shouldn't just do that? (Note that this also probably allows us to skip all the searching for $field_item in the first place.)
At that point, the hooks would receive something like this:
Much simpler, I think.
Comment #73
BerdirStill not sure what's bizarre about $field_item. But I agree that passing a File entity makes more sense, especially in the light of #1446464: Get rid of file_field_load() - shouldn't load all file object data with field load - only file ID, which will remove the additional file properties from that array and just leave us with fid.
The thing is, that we will loose certain information that is *only* in there, like the size of images or the alt text of a file. No idea why you'd need that in a access hook, but who knows.
Comment #74
BerdirOk, re-rolled with the $file_item => $file changes. If we want to pass $file_item as well then we need to add yet another argument to or $context for both hooks.
I guess better test coverage for all these checks and special cases and to verify that all arguments are passed correctly wouldn't hurt...
Comment #76
Berdir#74: file-file-download-context-1245220-73.patch queued for re-testing.
Comment #77
BerdirRemoved $entity_type from both hooks and instead typed $entity.
Comment #79
BerdirForgot to convert field_module_test. And yay, entity_extract_ids(), begone from that function! ;)
Comment #80
Berdir#79: file-file-download-context-1245220-79.patch queued for re-testing.
Comment #82
corvus_ch CreditAttribution: corvus_ch commentedComment #83
corvus_ch CreditAttribution: corvus_ch commentedMade patch applying to current 8.x branch.
Comment #84
chx CreditAttribution: chx commentedI have reviewed this several times and it makes sense and it is a good one.
Comment #85
catchYes this looks great to me as well. Committed/pushed to 8.x, thanks!
Comment #86
David_Rothstein CreditAttribution: David_Rothstein commentedThis needs a change notification, right? (Actually, there were API changes in this issue twice, since the original commit made one too. But we only have to document the final change compared to Drupal 7.)
I think the backport to D7 is not critical (as far as I remember, at most it's backporting a test, if anything needs to be done at all?), but the change notification is, of course.
Comment #87
David_Rothstein CreditAttribution: David_Rothstein commentedActually, some of the hook_file_download_access_alter() documentation introduced here doesn't make sense, since it's still referencing "field item".
The attached patch fixes that, and does a tiny bit of extra docs cleanup also (basically to keep the documentation of hook_file_download_access() and hook_file_download_access_alter() the same, given that I have to change the latter in this patch).
Comment #88
David_Rothstein CreditAttribution: David_Rothstein commentedI forgot that another thing which needed backport to Drupal 7 is #1143460: hook_file_download_access_alter missing entity argument, but I went ahead and reopened that now (it was previously closed as a duplicate), since for Drupal 7 I think that will be simpler to handle in its own issue - the backport might have to be very different from the change that went into Drupal 8.
Comment #90
David_Rothstein CreditAttribution: David_Rothstein commentedEr, that definitely wasn't my patch which did that. HEAD is broken.
(In other news, this issue title just keeps getting longer and longer...)
Comment #91
David_Rothstein CreditAttribution: David_Rothstein commentedOK, looks like the fix for that is simple.
I'm keeping my docs changes in this patch also, but it's committable without them if truly necessary.
Comment #92
David_Rothstein CreditAttribution: David_Rothstein commentedBy the way, it looks like what happened here (with the test failures) is that this issue and #1184272: Remove deprecated $conditions support from entity controller were committed around the same time, but they didn't play nicely together.
Comment #93
chx CreditAttribution: chx commentedOh DOH.
Comment #94
webchickOops. :)
Committed and pushed to 8.x. Thanks!
Comment #95
David_Rothstein CreditAttribution: David_Rothstein commentedComment #96
BerdirOk, I seriously messed up :)
The test implementation has not been updated.
Comment #97
Dave ReidConfirmed and RTBCd.
Comment #98
webchickCommitted and pushed the test fix to 8.x.
Back to active for the change notice.
Comment #99
BerdirYay!
Change notice is here: http://drupal.org/node/1744812
We need to remember to update it (the alter part) once #1143460: hook_file_download_access_alter missing entity argument is changed.
Comment #100
chx CreditAttribution: chx commentedThe change notice looks fine to me.
Comment #101
tim.plunkettPer #86.
Comment #102
BerdirI don't think this needs a backport. The tests are the same as the ones that already exist in 7.x, the only thing is the broken alter hook, for which there is a separate issue.