--userns-block-fd can hang when given a closed descriptor

Open Beginner friendly
#826 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
72/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
c, linux

Research direction

Start by reading the argument parsing for --userns-block-fd and the setup code around bubblewrap.c:3179-3180, where the supplied descriptor is read and closed. Check how child_wait_fd and setup_finished_pipe are allocated, then run both reproductions from the issue. Done means closed descriptors are rejected with an error before setup can hang.

Written by the indexing model from the issue text.

Description

bubblewrap 0.13.1 accepts a closed --userns-block-fd descriptor and can reuse its number for its internal eventfd or, with --json-status-fd, its setup-completion pipe.

Both runs below hung until timeout -s KILL 20 killed them (status 137).

To reproduce:

bwrap --unshare-user --info-fd 1 --userns-block-fd 4 --ro-bind / / --proc /proc --dev /dev /bin/true 3<&- 4<&-

strace:

2865  openat(AT_FDCWD, "/proc", O_RDONLY|O_PATH) = 3
2865  eventfd2(0, EFD_CLOEXEC)          = 4
2865  clone(child_stack=NULL, flags=CLONE_NEWNS|CLONE_NEWUSER|SIGCHLD) = 2866
2866  read(4,  <unfinished ...>
2865  read(4, 0x7ffe9b5a5857, 1)        = -1 EINVAL (Invalid argument)
2865  write(4, "\1\0\0\0\0\0\0\0", 8)   = -1 EBADF (Bad file descriptor)

child_wait_fd gets descriptor 4. The parent's 1-byte read of opt_userns_block_fd fails with EINVAL. The parent closes that descriptor (bubblewrap.c:3180), which is also child_wait_fd. Its write to child_wait_fd fails with EBADF, leaving the child blocked.

With --json-status-fd:

bwrap --unshare-user --info-fd 1 --json-status-fd 2 --userns-block-fd 5 --ro-bind / / --proc /proc --dev /dev /bin/true 3<&- 4<&- 5<&- 6<&-

strace:

2939  openat(AT_FDCWD, "/proc", O_RDONLY|O_PATH) = 3
2939  eventfd2(0, EFD_CLOEXEC)          = 4
2939  pipe2([5, 6], O_CLOEXEC)          = 0
2939  clone(child_stack=NULL, flags=CLONE_NEWNS|CLONE_NEWUSER|SIGCHLD) = 2940
2940  read(4,  <unfinished ...>
2939  read(5,

opt_userns_block_fd is the read end of setup_finished_pipe (descriptor 5). The parent blocks in its read (bubblewrap.c:3179) before writing child_wait_fd. The child blocks in its read of child_wait_fd.

A patched build checks descriptors with fcntl (fd, F_GETFD) during argument parsing. Both commands returned status 1:

bwrap: Invalid fd: 4: Bad file descriptor
bwrap: Invalid fd: 5: Bad file descriptor
Dominant language
C
Stars
9.4k
Forks
408
Avg merge
6d 14h
Merged PRs (30d)
1

Getting set up

This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from containers/bubblewrap

All issues in containers/bubblewrap

Similar issues

More C issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.