@@ -124,6 +124,54 @@ var _ = Describe("podman machine init", func() {
124124 Expect (repeatSession .errorToString ()).To (ContainSubstring (fmt .Sprintf ("Error: machine %q already exists" , mb .names [0 ])))
125125 })
126126
127+ It ("init subid range check for rootless PinP" , func () {
128+ /* By default, a new user is assigned the following sub-ID ranges (see manual useradd):
129+ * SUB_UID_MIN=100000, SUB_GID_MIN=100000, SUB_UID_COUNT=65536, SUB_GID_COUNT=65536
130+ * This means the default sub-UID and sub-GID ranges are 100000–165535.
131+ *
132+ * When the container is run rootless by the user in WSL, ID mappings occur as follows:
133+ * Container ID 0 (root) maps to user ID on the host.
134+ * Container IDs 1–65536 map to IDs 100000–165535 on host (range previously mentioned).
135+ *
136+ * If a new user is created inside the container and used to build containers with
137+ * (rootless PinP), it will attempt to use the default sub-ID range (100000–165535). Given
138+ * the mapping, this means that the host must at least have a SUB_UID_COUNT and
139+ * SUB_GID_COUNT of 165536. Since 165536 would only allow rootless PinP for the first
140+ * user (with ID 1000), the check is run against a count of 166536 (=165536+1000) as to
141+ * provide additional margin.
142+ */
143+
144+ count_min := 166536
145+ i := new (initMachine )
146+ session , err := mb .setName (name ).setCmd (i .withImage (mb .imagePath ).withRunPlaybook (playbookPath ).withNow ()).run ()
147+ Expect (err ).ToNot (HaveOccurred ())
148+ Expect (session ).To (Exit (0 ))
149+
150+ // obtain the users subid range from the machine
151+ ssh := new (sshMachine )
152+ sshSession , err := mb .setName (name ).setCmd (ssh .withSSHCommand ([]string {"cat" , "/etc/subuid" , "/etc/subgid" })).run ()
153+ Expect (err ).ToNot (HaveOccurred ())
154+ Expect (sshSession ).To (Exit (0 ))
155+ output := strings .TrimSpace (sshSession .OutputToString ())
156+
157+ // subuid and subgid have the format 'USER:SUB_ID_MIN:SUB_ID_COUNT', for example
158+ // 'user:100000:65536', only count is of interest.
159+ re := regexp .MustCompile (`(?m):(\d+)$` )
160+ counts := re .FindAllStringSubmatch (output , - 1 )
161+
162+ // A user must exist in order to run podman rootless, a line in both subuid and subgid
163+ // should exist for it, so 2 lines in total.
164+ Expect (len (counts )).To (BeNumerically (">=" , 2 ), "expected at least 1 user/line in /etc/subuid and /etc/subgid each, got %d" , len (counts ))
165+
166+ // Verify the count. At the moment only 1 user is created in the machine. If multiple users
167+ // are ever created, this will check that all users have a sufficient subid range.
168+ for _ , count := range counts {
169+ n , err := strconv .Atoi (count [1 ])
170+ Expect (err ).ToNot (HaveOccurred ())
171+ Expect (n ).To (BeNumerically (">=" , count_min ), "expected last number %d to be >= %d" , n , count_min )
172+ }
173+ })
174+
127175 It ("run playbook" , func () {
128176 str := randomString ()
129177
0 commit comments