Pre-auth COPY in versioned_writes can result in a successful COPY that wouldn't have been authorized
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
OpenStack Object Storage (swift) |
Fix Released
|
Undecided
|
Unassigned | ||
OpenStack Security Advisory |
Won't Fix
|
Undecided
|
Unassigned | ||
OpenStack Security Notes |
Fix Released
|
Undecided
|
Vincenzo Di Somma |
Bug Description
There is an issue in the versioning feature of swift (found in the latest on master - 2.6/2.7.0). Exploiting the vulnerability would not damage the cluster, but can have some undesirable behavior.
Scenario 1:
A user can cause an existing object in another account to be copied - when that user is not authorized for that account.
- user1 has access to tenant1
- user2 does not have access to tenant1
- user1 creates a versioned container ("versioned_
- user1 creates a container for those versions to be stored ("versions")
- user1 PUTs an object version in "versioned_
- user2 PUTs an object version in "versioned_
- the "pre-authed" copy of content "a" to the "versions" container succeeds
- the last PUT fails with Forbidden. (content "b" is not saved)
- So, the end state is that user2 caused the latest myobject version to be copied to "versions",
which user2 should not have access to.
(Exploiting this, user2 can drive up the usage of User1 impacting consumption against the quota and billing costs)
- user2 PUTs an object version in "versioned_
- same thing as the last PUT attempt, but the timestamp in the filename of myobject in the "versions" container.
(X-Timestamp is same in old obj listing - but when/if swift restores a version, the filename timestamp is used as X-Timestamp)
- No new data is created here. The old object still has content "a".
Scenario 2:
Another flow involving the same issue which results in user1 getting unexpected results.
In this scenario, when user1 attempts to revert to a prior version of an object, it will not be that version.
Note there is a work-around, but the user must be very aware of the issue to detect what had happened.
- user1 PUTs myobject with content "a"
- user1 PUTs myobject with content "b", this moves content "a" to the versions container
- user2 PUTs myobject this moves content "b" to the versions container
- user1 DELETEs myobject; this moves content "b" to the versioned_container but User1 expects the content to be "a"
(Work-around: DELETE twice - then the original "a" would be in place - Note it was not lost.)
So in summary, the bug is that a user can cause bytes to go into the container were old versions are stored when this user does not have access to the associated account. Note that the user still cannot write to the formal location of this versioned object, and the user cannot influence the contents of the objects. There is also no way to write more bytes than the size of ONE copy of an authorized object. Note that the original object will always be preserved - and this does not allow an authorized user to remove any versions.
Suggestion on how this can be fixed:
Change to perform some authorization before the copy to old versions is made inside of _put_versioned_obj instead of the pre-authed request that is currently made. There is a comment in the code saying the pre_auth request is made in case the user has write access to the container, but not READ. It says this was allowed before middleware was in place. In this particular scenario, the user doesn't even have write access.
Changed in swift: | |
status: | New → Confirmed |
information type: | Private Security → Public |
Changed in ossn: | |
assignee: | nobody → Vincenzo Di Somma (vds) |
Changed in ossn: | |
status: | New → In Progress |
Changed in ossn: | |
status: | Fix Committed → Fix Released |
Since this report concerns a possible security risk, an incomplete security advisory task has been added while the core security reviewers for the affected project or projects confirm the bug and discuss the scope of any vulnerability along with potential solutions.