josch josch - 1 year ago 151
Linux Question

Executing mount system call from perl

How can the

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
program using
because I need to make a
system call that the
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.

reveals that what the
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
in a single call to the
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?


Thankfully ikegami was quick to point out what i did wrong when trying to use perl's
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
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);

flag just seems to be for backwards compatibility with kernel versions prior to 2.4. The important bits are
(for doing the bind mounting itself) and
(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
function call or just do the
systemcall because both work just as well :)

Answer Source

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);


$ perl -E'
   require "";
   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 "";
   my $ret = syscall(&SYS_mount, my $s="/proc", my $t="/path/to/my/mount/point", 0, 0, 0);
   say $ret;

$ strace perl -e'
   require "";
   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)
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download