From 9639b9625554183d0c4d8d072dccb84fedd2320f Mon Sep 17 00:00:00 2001 From: Craig Ingram Date: Fri, 7 Mar 2025 13:27:58 +0000 Subject: [PATCH] validate uid/gid Signed-off-by: Craig Ingram --- oci/spec_opts.go | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/oci/spec_opts.go b/oci/spec_opts.go index 718c482..2101642 100644 --- a/oci/spec_opts.go +++ b/oci/spec_opts.go @@ -20,6 +20,7 @@ import ( "context" "encoding/json" "fmt" + "math" "io/ioutil" "os" "path/filepath" @@ -473,6 +474,20 @@ func WithUser(userstr string) SpecOpts { defer ensureAdditionalGids(s) setProcess(s) s.Process.User.AdditionalGids = nil + // While the Linux kernel allows the max UID to be MaxUint32 - 2, + // and the OCI Runtime Spec has no definition about the max UID, + // the runc implementation is known to require the UID to be <= MaxInt32. + // + // containerd follows runc's limitation here. + // + // In future we may relax this limitation to allow MaxUint32 - 2, + // or, amend the OCI Runtime Spec to codify the implementation limitation. + const ( + minUserID = 0 + maxUserID = math.MaxInt32 + minGroupID = 0 + maxGroupID = math.MaxInt32 + ) // For LCOW it's a bit harder to confirm that the user actually exists on the host as a rootfs isn't // mounted on the host and shared into the guest, but rather the rootfs is constructed entirely in the @@ -489,8 +504,8 @@ func WithUser(userstr string) SpecOpts { switch len(parts) { case 1: v, err := strconv.Atoi(parts[0]) - if err != nil { - // if we cannot parse as a uint they try to see if it is a username + if err != nil || v < minUserID || v > maxUserID { + // if we cannot parse as an int32 then try to see if it is a username return WithUsername(userstr)(ctx, client, c, s) } return WithUserID(uint32(v))(ctx, client, c, s) @@ -501,12 +516,13 @@ func WithUser(userstr string) SpecOpts { ) var uid, gid uint32 v, err := strconv.Atoi(parts[0]) - if err != nil { + if err != nil || v < minUserID || v > maxUserID { username = parts[0] } else { uid = uint32(v) } - if v, err = strconv.Atoi(parts[1]); err != nil { + v, err = strconv.Atoi(parts[1]) + if err != nil || v < minGroupID || v > maxGroupID { groupname = parts[1] } else { gid = uint32(v) -- 2.43.0