LIBUSERBINDMOUNT(3)
π LIBUSERBINDMOUNT(3) π
okay bestie, sit down, hydrate, and let me tell you about LIBUSERBINDMOUNT(3) from the Linux Programmer's Manual β this is the lib that lets you bind-mount inside user-namespaces and it is genuinely so underrated. no cap. π«Ά
β¨ NAME β¨
userbindmount, userbindmount_unshare, userbindmount_set_cap_sysadm, userbindmount_string, userbindmount_data, userbindmount_fd β bind-mount in user-namespaces. that's the whole vibe. π
π SYNOPSIS π
#include <userbindmount.h>
int userbindmount(const char *source, const char *target);
int userbindmount_unshare(void);
int userbindmount_set_cap_sysadm(void);
int userbindmount_string(const char *string, const char *target, mode_t mode);
int userbindmount_data(const void *data, size_t count, const char *target, mode_t mode);
int userbindmount_fd(int fd, const char *target, mode_t mode);
these functions are provided by libuserbindmount. link with -luserbindmount. don't forget it, i'm begging π
πΈ DESCRIPTION πΈ
Libuserbindmount is a library giving you support for bind mount in user userspaces. it's giving "i want mount privileges but make it unprivileged." iconic honestly.
userbindmount bind mounts source on destination. and if that's not permitted in the current namespace? it literally creates (unshare) a new user-namespace. problem solved, main character energy. π
userbindmount_unshare creates a new user-namespace where bind mount is allowed. that's it. that's the function.
userbindmount_set_cap_sysadm adds the CAP_SYS_ADMIN ambient capability to the current namespace so that the ability of bind mount files and directories can be exported to new programs (ambient capabilities survive to execve(2)). so the power travels with you, like a little crown you can pass down. π
userbindmount_string bind-mounts on destination a temporary file whose (text) contents is provided by string. The temporary file is automatically deleted when the namespace is closed or the file/directory unmounted. self-cleaning, we love a low-maintenance queen. β¨
userbindmount_data bind-mounts on destination a temporary file whose (binary) contents is provided by data and has the size of count bytes. The temporary file is automatically deleted when the namespace is closed or the file/directory unmounted. same energy, but for binary. πΎ
userbindmount_fd bind-mounts on destination a temporary file whose contents is read from the by the file descriptor fd (up to the end of file). The temporary file is automatically deleted when the namespace is closed or the file/directory unmounted. read it, mount it, forget it. π¦
π« RETURN VALUE π«
All the functions provided by libuserbindmount return 0 in case of success. -1 is returned elseways and errno is set appropriately. so like, check your return values, bestie, i'm not gonna do it for you. π
β NOTES β
Libuserbindmount fails if user namespaces have not been configured in the running kernel and enabled for users. on Debian the sysctl knob kernel.unprivileged_userns_clone must be set to 1.
π¨ fr fr, if you skipped that sysctl and nothing works, that's why. it's not you, it's the kernel config.
π EXAMPLES π
the following excerpts of C code shows the use of libuserbindmount: the inclusion of the header file for this library is required:
#include <usrbindmount.h>
bind-mount /tmp/resolv.conf on /etc/resolv.conf:
userbindmount("/tmp/resolv.conf", "/etc/resolv.conf");
bind-mount a string on /etc/resolv.conf:
userbindmount_string("nameserver 9.9.9.90, "/etc/resolv.conf", 0600);
bind-mount a binary data on /proc/self/cmdline:
static char fakeargv[] = {'c','m','d',0,
'a','r','g','1',0,
'a','r','g','2',0,
0};
userbindmount_data(fakeargv, sizeof(fakeargv), "/proc/self/cmdline", 0600);
bind-mount the data read from a file descriptor on /etc/resolv.conf:
userbindmount_fd(STDIN_FILENO, "/etc/resolv.conf", 0600);
bind-mount several files or directories:
userbindmount("/tmp/resolv.conf", "/etc/resolv.conf");
userbindmount("/tmp/passwd", "/etc/passwd");
userbindmount("/tmp/hosts", "/etc/hosts");
Only the first userbindmount creates a new namespace if needed. so you don't gotta unshare four times, she's efficient. π
π¦ the program that does the whole thing π¦
the following program creates a namespace and runs a program in it. In the new namespace bind-mount is allowed.
#include <stdio.h>
#include <unistd.h>
#include <userbindmount.h>
int main(int argc, char *argv[]) {
userbindmount_unshare();
userbindmount_set_cap_sysadm();
execvp(argv[1], argv+1);
}
It can be compiled and tested in the following way:
$ gcc -o unshare_sysadm unshare_sysadm.c -luserbindmount
$ unshare_sysadm bash
$ cat /etc/resolv.conf
nameserver 127.0.0.1
$ echo "nameserver 9.9.9.9" > /tmp/resolv.conf
$ busybox mount --bind /tmp/resolv.conf /etc/resolv.conf
$ cat /etc/resolv.conf
nameserver 9.9.9.9
$ exit
$
please note that in the example the mount command by busybox has been used instead of the standard mount by util-linux. In fact the standard mount command has not been updated to support the capabilities, and forbids the access to the mount system call if the effective user is not root, denying in this way a legal operation.
π yeah. the standard mount is gatekeeping a perfectly legal operation because the effective user isn't root. busybox said "i got you." and that's the tea.
π SEE ALSO π
mount(2), mount(8), user_namespaces(7)
π BUGS π
Bug reports should be addressed to <info@virtualsquare.org>. be nice, they're doing great work. π«Ά
π AUTHORS π
Renzo Davoli <renzo@cs.unibo.it> β legend behaviour, honestly. π
VirtualSquare, dated 2017-08-22, and this whole page is LIBUSERBINDMOUNT(3) β that's a wrap bestie, go bind-mount something responsibly. mwah. πβ¨π
π¦ where this page comes from
- debian bookworm: libuserbindmount-dev 0.1-3 Β· LGPL-2.1-or-later
- debian trixie: libuserbindmount-dev 0.1-3 Β· LGPL-2.1-or-later
- ubuntu jammy: libuserbindmount-dev 0.1-2 Β· LGPL-2.1-or-later
- ubuntu noble: libuserbindmount-dev 0.1-3 Β· LGPL-2.1-or-later
- ubuntu questing: libuserbindmount-dev 0.1-3
- ubuntu resolute: libuserbindmount-dev 0.1-3build1 Β· LGPL-2.1-or-later
- ubuntu stonking: libuserbindmount-dev 0.1-3build1 Β· LGPL-2.1-or-later
- Copyright (C) 2017 Renzo Davoli. University of Bologna. <renzo@cs.unibo.it>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms