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]

Reply via email to