How can the mount
system call be done from perl? The following:
$ret = syscall(&SYS_mount, "/proc", "/path/to/my/mount/point", 0, 0, 0);
results in:
Modification of a read-only value attempted at ...
I cannot call the mount
program using system
because I need to make a mount()
system call that the mount
program doesn't seem to be capable of. More specifically, I need to call:
mount("/proc", "/path/to/my/mpoint/point", NULL, MS_REC|MS_PRIVATE|MS_BIND, NULL);
But if I try to run the following with an unprivileged unshared mount linux namespace:
mount --make-rprivate --bind /proc /path/to/my/mountpoint
Then I get the following error:
mount: wrong fs type, bad option, bad superblock on /proc,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail or so.
Using strace
reveals that what the mount
program actually does is to call:
mount("/proc", "/path/to/my/mountpoint", ..., MS_MGC_VAL|MS_BIND, NULL);
mount("none", "/path/to/my/mointpoint", NULL, MS_REC|MS_PRIVATE, NULL);
But this splitting of options does not work. I need MS_BIND
and MS_REC|MS_PRIVATE
in a single call to the mount
system call for it to work in an unprivileged unshared mount namespace.
So how can I do my initial system call in perl without the error message about an attempt of a modification of a read-only value?
edit:
Thankfully ikegami was quick to point out what i did wrong when trying to use perl's syscall
function but in case somebody finds this when searching for how to bind mount a directory from within an unprivileged mount namespace with just the mount
command line utility, here is how:
mount --rbind /proc /path/to/my/mountpoint
This in turn will call the following syscall internally:
mount("proc", "/path/to/my/mountpoint", ..., MS_MGC_VAL|MS_BIND|MS_REC, 0);
The MS_MGC_VAL
flag just seems to be for backwards compatibility with kernel versions prior to 2.4. The important bits are MS_BIND
(for doing the bind mounting itself) and MS_REC
(for doing it recursively so that directories that have their content hidden by other mounts being done into them do not have their content exposed in the mount namespace).
So now I have to decide whether I go with a perl system
function call or just do the mount
systemcall because both work just as well :)
syscall
refuses to pass a pointer to the string buffer of a constant since it has no idea if the argument is char *
or const char *
.
You can't use a string literal (or other read-only string) as an argument to syscall because Perl has to assume that any string pointer might be written through
The solution is simple. Just copy the constant into a variable first.
my $ret = syscall(&SYS_mount, my $s="/proc", my $t="/path/to/my/mount/point", 0, 0, 0);
Test:
$ perl -E'
require "syscall.ph";
my $ret = syscall(&SYS_mount, "/proc", "/path/to/my/mount/point", 0, 0, 0);
say $ret;
'
Modification of a read-only value attempted at -e line 3.
$ perl -E'
require "syscall.ph";
my $ret = syscall(&SYS_mount, my $s="/proc", my $t="/path/to/my/mount/point", 0, 0, 0);
say $ret;
'
-1
$ strace perl -e'
require "syscall.ph";
syscall(&SYS_mount, my $s="/proc", my $t="/path/to/my/mount/point", 0, 0, 0);
' 2>&1 | grep mount
mount("/proc", "/path/to/my/mount/point", NULL, 0, NULL) = -1 ENOENT (No such file or directory)
You can find a full implementation in Perl here: https://github.com/i-MSCP/imscp/blob/1.5.x/engine/PerlLib/iMSCP/Mount.pm
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With