oci-util: fix and harden oci_registry_is_valid()

- Pass colon+1 (port string) instead of s (hostname) to safe_atou16,
  so host:port registries are no longer always rejected.
- Switch to safe_atou16_full() with base-10 and strict flags to reject
  non-decimal port forms (hex, octal, leading whitespace, sign prefix)
  that would produce malformed URL authorities.
- Reject empty host explicitly via isempty() guard (covers both NULL
  and empty-string input), and guard colon == n to reject ':port' form,
  since dns_name_is_valid('') == 1 (DNS root) would otherwise accept
  empty host as valid.
- Wrap overlong line to fit 109-column limit.
- Add test coverage for oci_registry_is_valid().

Signed-off-by: dongshengyuan <dongshengyuan@uniontech.com>
(cherry picked from commit 7020bd3d82)
This commit is contained in:
dongshengyuan
2026-06-22 13:16:32 +08:00
committed by Zbigniew Jędrzejewski-Szmek
parent bdec22be36
commit 01d79ea250
2 changed files with 37 additions and 2 deletions

View File

@@ -51,13 +51,16 @@ bool oci_image_is_valid(const char *n) {
int oci_registry_is_valid(const char *n) {
int r;
if (!n)
if (isempty(n))
return false;
const char *colon = strchr(n, ':');
if (!colon)
return dns_name_is_valid(n);
if (colon == n) /* empty host, e.g. ":5000" */
return false;
_cleanup_free_ char *s = strndup(n, colon - n);
if (!s)
return -ENOMEM;
@@ -67,7 +70,10 @@ int oci_registry_is_valid(const char *n) {
return r;
uint16_t port;
return safe_atou16(s, &port) >= 0 && port != 0;
return safe_atou16_full(colon + 1,
10 | SAFE_ATO_REFUSE_LEADING_WHITESPACE |
SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_ZERO,
&port) >= 0 && port != 0;
}
bool oci_tag_is_valid(const char *n) {

View File

@@ -19,4 +19,33 @@ TEST(urlescape) {
test_urlescape_one("müffel", "m%c3%bcffel");
}
TEST(oci_registry_is_valid) {
/* plain hostname — valid */
assert_se(oci_registry_is_valid("localhost") > 0);
assert_se(oci_registry_is_valid("registry.example.com") > 0);
/* host:port — valid */
assert_se(oci_registry_is_valid("localhost:5000") > 0);
assert_se(oci_registry_is_valid("registry.example.com:443") > 0);
assert_se(oci_registry_is_valid("registry.io:1") > 0);
assert_se(oci_registry_is_valid("registry.io:65535") > 0);
/* port 0 — invalid */
assert_se(oci_registry_is_valid("localhost:0") == 0);
/* port overflow */
assert_se(oci_registry_is_valid("localhost:65536") == 0);
/* non-decimal port forms — rejected */
assert_se(oci_registry_is_valid("localhost:0x50") == 0); /* hex */
assert_se(oci_registry_is_valid("localhost:017") == 0); /* leading zero */
assert_se(oci_registry_is_valid("localhost:+80") == 0); /* plus sign */
assert_se(oci_registry_is_valid("localhost: 80") == 0); /* leading space */
/* invalid hostname */
assert_se(oci_registry_is_valid(":5000") == 0);
assert_se(oci_registry_is_valid("") == 0);
assert_se(oci_registry_is_valid(NULL) == 0);
}
DEFINE_TEST_MAIN(LOG_DEBUG);