File: namespaces.bats

package info (click to toggle)
golang-github-containers-buildah 1.19.6%2Bdfsg1-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 5,020 kB
  • sloc: sh: 1,957; makefile: 199; perl: 173; awk: 12; ansic: 1
file content (394 lines) | stat: -rw-r--r-- 14,374 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
#!/usr/bin/env bats

load helpers

@test "already-in-userns" {
  if test "$BUILDAH_ISOLATION" != "rootless" -o $UID == 0 ; then
    skip "BUILDAH_ISOLATION = $BUILDAH_ISOLATION"
  fi

  _prefetch alpine
  run_buildah from --signature-policy ${TESTSDIR}/policy.json --quiet alpine
  expect_output "alpine-working-container"
  ctr="$output"

  run_buildah unshare buildah run --isolation=oci "$ctr" echo hello
  expect_output "hello"
}

@test "user-and-network-namespace" {
  skip_if_chroot
  skip_if_rootless

  mkdir -p $TESTDIR/no-cni-configs
  RUNOPTS="--cni-config-dir=${TESTDIR}/no-cni-configs ${RUNC_BINARY:+--runtime $RUNC_BINARY}"
  # Check if we're running in an environment that can even test this.
  run readlink /proc/self/ns/user
  echo "readlink /proc/self/ns/user -> $output"
  [ $status -eq 0 ] || skip "user namespaces not supported"
  run readlink /proc/self/ns/net
  echo "readlink /proc/self/ns/net -> $output"
  [ $status -eq 0 ] || skip "network namespaces not supported"
  mynetns="$output"

  # Generate the mappings to use for using-a-user-namespace cases.
  uidbase=$((${RANDOM}+1024))
  gidbase=$((${RANDOM}+1024))
  uidsize=$((${RANDOM}+1024))
  gidsize=$((${RANDOM}+1024))

  # Create a container that uses that mapping.
  _prefetch alpine
  run_buildah from --signature-policy ${TESTSDIR}/policy.json --quiet --userns-uid-map 0:$uidbase:$uidsize --userns-gid-map 0:$gidbase:$gidsize alpine
  ctr="$output"

  # Check that with settings that require a user namespace, we also get a new network namespace by default.
  run_buildah run $RUNOPTS "$ctr" readlink /proc/self/ns/net
  if [[ $output == $mynetns ]]; then
      expect_output "[output should not be '$mynetns']"
  fi

  # Check that with settings that require a user namespace, we can still try to use the host's network namespace.
  run_buildah run $RUNOPTS --net=host "$ctr" readlink /proc/self/ns/net
  expect_output "$mynetns"

  # Create a container that doesn't use that mapping.
  run_buildah from --signature-policy ${TESTSDIR}/policy.json --quiet alpine
  ctr="$output"

  # Check that with settings that don't require a user namespace, we don't get a new network namespace by default.
  run_buildah run $RUNOPTS "$ctr" readlink /proc/self/ns/net
  expect_output "$mynetns"

  # Check that with settings that don't require a user namespace, we can request to use a per-container network namespace.
  run_buildah run $RUNOPTS --net=container "$ctr" readlink /proc/self/ns/net
  if [[ $output == $mynetns ]]; then
      expect_output "[output should not be '$mynetns']"
  fi

  run_buildah run $RUNOPTS --net=private "$ctr" readlink /proc/self/ns/net
  if [[ $output == $mynetns ]]; then
      expect_output "[output should not be '$mynetns']"
  fi
}

@test "idmapping" {
  mkdir -p $TESTDIR/no-cni-configs
  RUNOPTS="--cni-config-dir=${TESTDIR}/no-cni-configs ${RUNC_BINARY:+--runtime $RUNC_BINARY}"

  # Check if we're running in an environment that can even test this.
  run readlink /proc/self/ns/user
  echo "readlink /proc/self/ns/user -> $output"
  [ $status -eq 0 ] || skip "user namespaces not supported"
  mynamespace="$output"

  # Generate the mappings to use.
  uidbase=$((${RANDOM}+1024))
  gidbase=$((${RANDOM}+1024))
  uidsize=$((${RANDOM}+1024))
  gidsize=$((${RANDOM}+1024))
  # Test with no mappings.
  uidmapargs[0]=
  gidmapargs[0]=
  uidmaps[0]="0 0 4294967295"
  gidmaps[0]="0 0 4294967295"
  # Test with both UID and GID maps specified.
  uidmapargs[1]="--userns-uid-map=0:$uidbase:$uidsize"
  gidmapargs[1]="--userns-gid-map=0:$gidbase:$gidsize"
  uidmaps[1]="0 $uidbase $uidsize"
  gidmaps[1]="0 $gidbase $gidsize"
  # Conditionalize some tests on the subuid and subgid files being present.
  if test -s /etc/subuid ; then
    if test -s /etc/subgid ; then
      # Look for a name that's in both the subuid and subgid files.
      for candidate in $(sed -e 's,:.*,,g' /etc/subuid); do
        if test $(sed -e 's,:.*,,g' -e "/$candidate/!d" /etc/subgid) == "$candidate"; then
          # Read the start of the subuid/subgid ranges.  Assume length=65536.
          userbase=$(sed -e "/^${candidate}:/!d" -e 's,^[^:]*:,,g' -e 's,:[^:]*,,g' /etc/subuid)
          groupbase=$(sed -e "/^${candidate}:/!d" -e 's,^[^:]*:,,g' -e 's,:[^:]*,,g' /etc/subgid)
          # Test specifying both the user and group names.
          uidmapargs[${#uidmaps[*]}]=--userns-uid-map-user=$candidate
          gidmapargs[${#gidmaps[*]}]=--userns-gid-map-group=$candidate
          uidmaps[${#uidmaps[*]}]="0 $userbase 65536"
          gidmaps[${#gidmaps[*]}]="0 $groupbase 65536"
          # Test specifying just the user name.
          uidmapargs[${#uidmaps[*]}]=--userns-uid-map-user=$candidate
          uidmaps[${#uidmaps[*]}]="0 $userbase 65536"
          gidmaps[${#gidmaps[*]}]="0 $groupbase 65536"
          # Test specifying just the group name.
          gidmapargs[${#gidmaps[*]}]=--userns-gid-map-group=$candidate
          uidmaps[${#uidmaps[*]}]="0 $userbase 65536"
          gidmaps[${#gidmaps[*]}]="0 $groupbase 65536"
          break
        fi
      done
      # Choose different names from the files.
      for candidateuser in $(sed -e 's,:.*,,g' /etc/subuid); do
        for candidategroup in $(sed -e 's,:.*,,g' /etc/subgid); do
          if test "$candidateuser" == "$candidate" ; then
            continue
          fi
          if test "$candidategroup" == "$candidate" ; then
            continue
          fi
          if test "$candidateuser" == "$candidategroup" ; then
            continue
          fi
          # Read the start of the ranges.  Assume length=65536.
          userbase=$(sed -e "/^${candidateuser}:/!d" -e 's,^[^:]*:,,g' -e 's,:[^:]*,,g' /etc/subuid)
          groupbase=$(sed -e "/^${candidategroup}:/!d" -e 's,^[^:]*:,,g' -e 's,:[^:]*,,g' /etc/subgid)
          # Test specifying both the user and group names.
          uidmapargs[${#uidmaps[*]}]=--userns-uid-map-user=$candidateuser
          gidmapargs[${#gidmaps[*]}]=--userns-gid-map-group=$candidategroup
          uidmaps[${#uidmaps[*]}]="0 $userbase 65536"
          gidmaps[${#gidmaps[*]}]="0 $groupbase 65536"
          break
        done
      done
    fi
  fi

  touch ${TESTDIR}/somefile
  mkdir ${TESTDIR}/somedir
  touch ${TESTDIR}/somedir/someotherfile
  chmod 700 ${TESTDIR}/somedir/someotherfile
  chmod u+s ${TESTDIR}/somedir/someotherfile

  for i in $(seq 0 "$((${#uidmaps[*]}-1))") ; do
    # Create a container using these mappings.
    echo "Building container with --signature-policy ${TESTSDIR}/policy.json --quiet ${uidmapargs[$i]} ${gidmapargs[$i]} alpine"
    _prefetch alpine
    run_buildah from --signature-policy ${TESTSDIR}/policy.json --quiet ${uidmapargs[$i]} ${gidmapargs[$i]} alpine
    ctr="$output"

    # If we specified mappings, expect to be in a different namespace by default.
    run_buildah run $RUNOPTS "$ctr" readlink /proc/self/ns/user
    [ "$output" != "" ]
    case x"${uidmapargs[$i]}""${gidmapargs[$i]}" in
    x)
      if test "$BUILDAH_ISOLATION" != "chroot" -a "$BUILDAH_ISOLATION" != "rootless" ; then
        expect_output "$mynamespace"
      fi
      ;;
    *)
      [ "$output" != "$mynamespace" ]
      ;;
    esac
    # Check that we got the mappings that we expected.
    run_buildah run $RUNOPTS "$ctr" cat /proc/self/uid_map
    [ "$output" != "" ]
    uidmap=$(sed -E -e 's, +, ,g' -e 's,^ +,,g' <<< "$output")
    run_buildah run $RUNOPTS "$ctr" cat /proc/self/gid_map
    [ "$output" != "" ]
    gidmap=$(sed -E -e 's, +, ,g' -e 's,^ +,,g' <<< "$output")
    echo With settings "$map", expected UID map "${uidmaps[$i]}", got UID map "${uidmap}", expected GID map "${gidmaps[$i]}", got GID map "${gidmap}".
    expect_output --from="$uidmap" "${uidmaps[$i]}"
    expect_output --from="$gidmap" "${gidmaps[$i]}"
    rootuid=$(sed -E -e 's,^([^ ]*) (.*) ([^ ]*),\2,' <<< "$uidmap")
    rootgid=$(sed -E -e 's,^([^ ]*) (.*) ([^ ]*),\2,' <<< "$gidmap")

    # Check that if we copy a file into the container, it gets the right permissions.
    run_buildah copy --chown 1:1 "$ctr" ${TESTDIR}/somefile /
    run_buildah run $RUNOPTS "$ctr" stat -c '%u:%g' /somefile
    expect_output "1:1"

    # Check that if we copy a directory into the container, its contents get the right permissions.
    run_buildah copy "$ctr" ${TESTDIR}/somedir /somedir
    run_buildah run $RUNOPTS "$ctr" stat -c '%u:%g' /somedir
    expect_output "0:0"
    run_buildah mount "$ctr"
    mnt="$output"
    run stat -c '%u:%g %a' "$mnt"/somedir/someotherfile
    [ $status -eq 0 ]
    expect_output "$rootuid:$rootgid 4700"
    run_buildah run $RUNOPTS "$ctr" stat -c '%u:%g %a' /somedir/someotherfile
    expect_output "0:0 4700"

    # Check that a container with mapped-layer can be committed.
    run_buildah commit "$ctr" localhost/alpine-working:$i
  done
}

general_namespace() {
  mkdir -p $TESTDIR/no-cni-configs
  RUNOPTS="--cni-config-dir=${TESTDIR}/no-cni-configs ${RUNC_BINARY:+--runtime $RUNC_BINARY}"

  # The name of the /proc/self/ns/$link.
  nstype="$1"
  # The flag to use, if it's not the same as the namespace name.
  nsflag="${2:-$1}"

  # Check if we're running in an environment that can even test this.
  run readlink /proc/self/ns/"$nstype"
  echo "readlink /proc/self/ns/$nstype -> $output"
  [ $status -eq 0 ] || skip "$nstype namespaces not supported"
  mynamespace="$output"

  # Settings to test.
  types[0]=
  types[1]=container
  types[2]=host
  types[3]=/proc/$$/ns/$nstype
  types[4]=private
  types[5]=ns:/proc/$$/ns/$nstype

  _prefetch alpine
  for namespace in "${types[@]}" ; do
    # Specify the setting for this namespace for this container.
    run_buildah from --signature-policy ${TESTSDIR}/policy.json --quiet --"$nsflag"=$namespace alpine
    [ "$output" != "" ]
    ctr="$output"

    # Check that, unless we override it, we get that setting in "run".
    run_buildah run $RUNOPTS "$ctr" readlink /proc/self/ns/"$nstype"
    [ "$output" != "" ]
    case "$namespace" in
    ""|container|private)
      [ "$output" != "$mynamespace" ]
      ;;
    host)
      expect_output "$mynamespace"
      ;;
    /*)
      expect_output "$(readlink $namespace)"
      ;;
    esac

    for different in $types ; do
      # Check that, if we override it, we get what we specify for "run".
      run_buildah run $RUNOPTS --"$nsflag"=$different "$ctr" readlink /proc/self/ns/"$nstype"
      [ "$output" != "" ]
      case "$different" in
      ""|container|private)
        [ "$output" != "$mynamespace" ]
        ;;
      host)
        expect_output "$mynamespace"
        ;;
      /*)
        expect_output "$(readlink $namespace)"
        ;;
      esac
    done

  done
}

@test "ipc-namespace" {
  skip_if_chroot
  skip_if_rootless

  general_namespace ipc
}

@test "net-namespace" {
  skip_if_chroot
  skip_if_rootless

  general_namespace net
}

@test "network-namespace" {
  skip_if_chroot
  skip_if_rootless

  general_namespace net network
}

@test "pid-namespace" {
  skip_if_chroot
  skip_if_rootless

  general_namespace pid
}

@test "user-namespace" {
  skip_if_chroot
  skip_if_rootless

  general_namespace user userns
}

@test "uts-namespace" {
  skip_if_chroot
  skip_if_rootless

  general_namespace uts
}

@test "combination-namespaces" {
  skip_if_chroot
  skip_if_rootless

  _prefetch alpine
  # mnt is always per-container, cgroup isn't a thing OCI runtime lets us configure
  for ipc in host container private ; do
    for net in host container private; do
      for pid in host container private; do
        for userns in host container private; do
          for uts in host container private; do

            if test $userns == private -o $userns == container -a $pid == host ; then
              # We can't mount a fresh /proc, and OCI runtime won't let us bind mount the host's.
              continue
            fi

            echo "buildah from --signature-policy ${TESTSDIR}/policy.json --ipc=$ipc --net=$net --pid=$pid --userns=$userns --uts=$uts alpine"
            run_buildah from --signature-policy ${TESTSDIR}/policy.json --quiet --ipc=$ipc --net=$net --pid=$pid --userns=$userns --uts=$uts alpine
            [ "$output" != "" ]
            ctr="$output"
            run_buildah run $ctr pwd
            [ "$output" != "" ]
            run_buildah run --tty=true  $ctr pwd
            [ "$output" != "" ]
            run_buildah run --tty=false $ctr pwd
            [ "$output" != "" ]
          done
        done
      done
    done
  done
}

@test "idmapping-and-squash" {
	createrandom ${TESTDIR}/randomfile
	run_buildah from --userns-uid-map 0:32:16 --userns-gid-map 0:48:16 scratch
	cid=$output
	run_buildah copy "$cid" ${TESTDIR}/randomfile /
	run_buildah copy --chown 1:1 "$cid" ${TESTDIR}/randomfile /randomfile2
	run_buildah commit --squash --signature-policy ${TESTSDIR}/policy.json --rm "$cid" squashed
	run_buildah from --quiet squashed
	cid=$output
	run_buildah mount $cid
	mountpoint=$output
	run stat -c %u:%g $mountpoint/randomfile
	[ "$status" -eq 0 ]
        expect_output "0:0"

	run stat -c %u:%g $mountpoint/randomfile2
	[ "$status" -eq 0 ]
        expect_output "1:1"
}

@test "invalid userns-uid-map userns-gid-map" {
	run_buildah 125 from --userns-uid-map 16  --userns-gid-map 0:48:16 scratch
	expect_output 'error initializing ID mappings: userns-uid-map setting is malformed expected ["uint32:uint32:uint32"]: ["16"]'

	run_buildah 125 from --userns-uid-map 0:32:16  --userns-gid-map 16 scratch
	expect_output 'error initializing ID mappings: userns-gid-map setting is malformed expected ["uint32:uint32:uint32"]: ["16"]'

	run_buildah 125 bud --userns-uid-map a  --userns-gid-map bogus bud/from-scratch
	expect_output 'error initializing ID mappings: userns-uid-map setting is malformed expected ["uint32:uint32:uint32"]: ["a"]'

	run_buildah 125 bud --userns-uid-map 0:32:16 --userns-gid-map bogus bud/from-scratch
	expect_output 'error initializing ID mappings: userns-gid-map setting is malformed expected ["uint32:uint32:uint32"]: ["bogus"]'

	run_buildah from --userns-uid-map 0:32:16  scratch
}

@test "idmapping-syntax" {
  run_buildah from --signature-policy ${TESTSDIR}/policy.json --quiet --userns-uid-map=0:10000:65536 alpine

  run_buildah 125 from --signature-policy ${TESTSDIR}/policy.json --quiet --userns-gid-map=0:10000:65536 alpine
  expect_output --substring "userns-gid-map can not be used without --userns-uid-map"
}