Siyao Meng created HDDS-17249:
---------------------------------
Summary: Snapshot create does not check the bucket again at apply
Key: HDDS-17249
URL: https://issues.apache.org/jira/browse/HDDS-17249
Project: Apache Ozone
Issue Type: Bug
Reporter: Siyao Meng
h3. Mechanism
{{OMSnapshotCreateRequest.preExecute}} resolves the bucket and, when admin
authorization is enabled, checks that the caller owns it or is an admin. The
CreateSnapshot request then carries only the caller, the volume and bucket
names, the snapshot name and ID and the creation time.
{{OMSnapshotCreateRequest.validateAndUpdateCache}} looks the bucket up again by
name under the bucket lock ({{getBucketInfo}}, which reads the bucket table
cache) and uses the result without checking it:
* {{omBucketInfo.getUsedBytes()}} is called on the lookup result without a null
check, so a missing bucket ends in a {{NullPointerException}} instead of
{{BUCKET_NOT_FOUND}}.
* The snapshot is created on whatever bucket the lookup returns, and the owner
or admin check is not made against that bucket.
The dereference came with the snapshot referenced size (HDDS-9159); the owner
or admin check has been in {{preExecute}} only since the request was added.
h3. Trigger
At apply, the bucket table cache has no entry for the bucket, or holds a bucket
other than the one {{preExecute}} checked (a different objectID).
h3. Impact
Reproduced on unmodified source through the request classes, with the bucket
table cache entry changed directly before {{validateAndUpdateCache}}:
* No bucket: {{validateAndUpdateCache}} throws {{NullPointerException: Cannot
invoke "OmBucketInfo.getUsedBytes()" because "omBucketInfo" is null}}.
* A bucket with another owner and objectID: the apply returns OK and the
snapshot is created on it, with no owner or admin check against it.
h3. Reproduction
No standalone reproduction is attached. The two tests in the patch run the real
{{preExecute}} and {{validateAndUpdateCache}} against a real
{{OmMetadataManagerImpl}} and change only the bucket table cache entry in
between; both fail on unmodified source (see Patch).
h3. Patch
[^MC-1-check-bucket-again-when-applying-snapshot-create.patch], against
20d95ed37fe35013b5320713665db03c06ee36fa. It also applies to master at
64d4a791502.
{{validateAndUpdateCache}} now throws {{OMException(BUCKET_NOT_FOUND)}} when
{{getBucketInfo}} returns null and, when admin authorization is enabled,
re-checks owner or admin against the bucket it found, with the rule
{{preExecute}} uses (moved into a small helper used by both). The exception
takes the request's normal error path: the snapshot chain and the snapshot
table cache are untouched, the locks and the snapshot limit reservation taken
by {{OmSnapshotManager.snapshotLimitCheck}} are released, and an error response
is returned. Other bucket requests also check authorization at apply, for
example {{OMBucketSetPropertyRequest}} with the same owner or admin rule.
A stricter alternative is to bind the snapshot to the bucket objectID recorded
in {{preExecute}}, in a new optional {{CreateSnapshotRequest}} field, and
reject at apply when it differs; that would also reject a recreate by the same
owner, which the authorization check accepts. The null check is needed in
either variant. The open pull request apache/ozone#10965 (HDDS-16060) adds a
check on the same {{omBucketInfo}} right after this lookup; the two changes
touch the same lines, and whichever lands second keeps the null check ahead of
that check.
The check changes what an OM applies for such an entry. With the current
upgrade, which goes through OM prepare, OMs of two versions do not apply the
same entries; under zero downtime upgrade this apply change, like others, would
need a version flag.
Covered by {{testValidateAndUpdateCacheBucketNotFound}} and
{{testValidateAndUpdateCacheChecksCurrentBucketOwner}} (owner on the bucket
{{preExecute}} checked, replacement bucket with another owner, and an admin on
that bucket) in the existing {{TestOMSnapshotCreateRequest}}. Without the
change they fail with the {{NullPointerException}} above and with "expected:
<PERMISSION_DENIED> but was: <OK>". With it the snapshot request, response and
service unit suites pass (270 tests), as do {{TestOzoneManagerSnapshotAcl}} and
{{TestOzoneManagerHASnapshot}} (67 tests), and checkstyle is clean.
Found by TLA+ model checking and code review of the OM volume, bucket and
snapshot lifecycle paths under HDDS-15926, on commit
20d95ed37fe35013b5320713665db03c06ee36fa. Checked against HDDS issues and
apache/ozone pull requests for duplicates before filing. Related but not a
duplicate: HDDS-16744 (snapshot limit counter not released for a retried
create). The attached patch is a proposal for review. Generated with Specula
(Claude Opus 5.5).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]