Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Executing mount system call from perl

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

like image 230
josch Avatar asked Oct 21 '15 15:10

josch


2 Answers

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)
like image 194
ikegami Avatar answered Nov 13 '22 14:11

ikegami


You can find a full implementation in Perl here: https://github.com/i-MSCP/imscp/blob/1.5.x/engine/PerlLib/iMSCP/Mount.pm

like image 32
Laurent DECLERCQ a.k.a Nuxwin Avatar answered Nov 13 '22 12:11

Laurent DECLERCQ a.k.a Nuxwin