This is an automated email from the ASF dual-hosted git repository.
priyeshkaratha pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new bc434323f30 HDDS-16393. Reject oversized Days values in
PutBucketLifecycle (#11290)
bc434323f30 is described below
commit bc434323f301130bccdac9bc8c42698e50f63291
Author: Priyesh Karatha <[email protected]>
AuthorDate: Wed Sep 23 13:25:40 2026 +0530
HDDS-16393. Reject oversized Days values in PutBucketLifecycle (#11290)
---
.../s3/endpoint/S3LifecycleConfiguration.java | 33 ++++++++++++----
.../endpoint/TestS3LifecycleConfigurationPut.java | 46 ++++++++++++++++++++++
2 files changed, 72 insertions(+), 7 deletions(-)
diff --git
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java
index f7d72421fe1..2327f9b759c 100644
---
a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java
+++
b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/endpoint/S3LifecycleConfiguration.java
@@ -138,18 +138,20 @@ public void setFilter(Filter filter) {
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Expiration")
public static class Expiration {
+ // Bound to XML as the raw text so out-of-range values can be rejected
explicitly, instead
+ // of JAXB's built-in Integer converter silently overflowing them (see
parseDays).
@XmlElement(name = "Days")
- private Integer days;
+ private String days;
@XmlElement(name = "Date")
private String date;
public Integer getDays() {
- return days;
+ return parseDays(days);
}
public void setDays(Integer days) {
- this.days = days;
+ this.days = days == null ? null : days.toString();
}
public String getDate() {
@@ -168,14 +170,30 @@ public void setDate(String date) {
@XmlRootElement(name = "AbortIncompleteMultipartUpload")
public static class AbortIncompleteMultipartUpload {
@XmlElement(name = "DaysAfterInitiation")
- private Integer daysAfterInitiation;
+ private String daysAfterInitiation;
public Integer getDaysAfterInitiation() {
- return daysAfterInitiation;
+ return parseDays(daysAfterInitiation);
}
public void setDaysAfterInitiation(Integer daysAfterInitiation) {
- this.daysAfterInitiation = daysAfterInitiation;
+ this.daysAfterInitiation = daysAfterInitiation == null ? null :
daysAfterInitiation.toString();
+ }
+ }
+
+ /**
+ * Parses a lifecycle day-count element, rejecting a value that does not fit
in an int instead
+ * of silently overflowing it the way JAXB's built-in Integer converter
would.
+ */
+ private static Integer parseDays(String value) {
+ if (value == null) {
+ return null;
+ }
+ try {
+ return Integer.parseInt(value.trim());
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid lifecycle configuration:
Days value '" + value
+ + "' is not a valid integer", e);
}
}
@@ -303,7 +321,8 @@ public OmLifecycleConfiguration
toOmLifecycleConfiguration(OzoneBucket ozoneBuck
if (ex.getCause() instanceof OMException) {
throw (OMException) ex.getCause();
}
- throw S3ErrorTable.newError(S3ErrorTable.INVALID_ARGUMENT,
ozoneBucket.getName(), ex);
+ throw S3ErrorTable.newError(S3ErrorTable.INVALID_ARGUMENT,
ozoneBucket.getName(), ex)
+ .withMessage(ex.getMessage());
} catch (IllegalStateException ex) {
throw S3ErrorTable.newError(S3ErrorTable.INVALID_ARGUMENT,
ozoneBucket.getName(), ex);
}
diff --git
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationPut.java
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationPut.java
index 1abace96ab4..0891b1dd8b9 100644
---
a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationPut.java
+++
b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/s3/endpoint/TestS3LifecycleConfigurationPut.java
@@ -321,6 +321,24 @@ public void
testPutInvalidAbortIncompleteMultipartUploadConfig() throws Exceptio
HTTP_BAD_REQUEST, INVALID_ARGUMENT.getCode());
}
+ @Test
+ public void
testPutLifecycleConfigurationWithExpirationDaysOverflowReportsSpecificMessage()
throws Exception {
+ // A day count that overflows a 32-bit int must be rejected, not silently
wrapped to an
+ // unrelated positive value that then gets persisted.
+ OS3Exception ex = assertThrows(OS3Exception.class,
+ () -> bucketEndpoint.put("bucket1", withExpirationDaysOverflow()));
+ assertEquals(HTTP_BAD_REQUEST, ex.getHttpCode());
+ assertEquals(INVALID_ARGUMENT.getCode(), ex.getCode());
+ assertEquals("Invalid lifecycle configuration: Days value "
+ + "'3323232323232323232323232323232323232323232' is not a valid
integer", ex.getErrorMessage());
+ }
+
+ @Test
+ public void
testPutLifecycleConfigurationWithAbortDaysAfterInitiationOverflow() throws
Exception {
+
testInvalidLifecycleConfiguration(TestS3LifecycleConfigurationPut::withAbortDaysAfterInitiationOverflow,
+ HTTP_BAD_REQUEST, INVALID_ARGUMENT.getCode());
+ }
+
private static InputStream onePrefix() {
String xml = ("<LifecycleConfiguration xmlns=\"http://s3.amazonaws" +
".com/doc/2006-03-01/\">" +
@@ -774,4 +792,32 @@ private static InputStream withAbortNegativeDays() {
return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
}
+
+ private static InputStream withExpirationDaysOverflow() {
+ String xml = "<LifecycleConfiguration
xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" +
+ "<Rule>" +
+ "<ID>overflow-days</ID>" +
+ "<Prefix>prefix/</Prefix>" +
+ "<Status>Enabled</Status>" +
+
"<Expiration><Days>3323232323232323232323232323232323232323232</Days></Expiration>"
+
+ "</Rule>" +
+ "</LifecycleConfiguration>";
+
+ return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+ }
+
+ private static InputStream withAbortDaysAfterInitiationOverflow() {
+ String xml = "<LifecycleConfiguration
xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">" +
+ "<Rule>" +
+ "<ID>overflow-abort</ID>" +
+ "<Prefix>uploads/</Prefix>" +
+ "<Status>Enabled</Status>" +
+ "<AbortIncompleteMultipartUpload>" +
+
"<DaysAfterInitiation>3323232323232323232323232323232323232323232</DaysAfterInitiation>"
+
+ "</AbortIncompleteMultipartUpload>" +
+ "</Rule>" +
+ "</LifecycleConfiguration>";
+
+ return new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]