Execution files located on shared folders, mount with "exec"

Discussion in 'Linux Guest OS Discussion' started by DietrichL3, Mar 9, 2021.

  1. DietrichL3

    DietrichL3 Bit Poster

    Messages:
    5
    Dear all,

    I run Fedora 32 on a MAC and Parallels 16.
    I compiled Parallels Tools for kernel 5.10, this worked fine.

    However, I cannot execute files which are located on the shared folder.
    Output from mount is:
    Code:
    root@fed30 Downloads]# mount  | grep Home
    Home on /media/psf/Home type prl_fs (rw,nosuid,nodev,noatime,sync,context=system_u:object_r:removable_t:s0,ttl=1000,share)
    When executing a executable
    Code:
    $ cat test.tcsh ;
    #!/usr/bin/tcsh
    $ ./test.tcsh
    ./xx: Invalid argument.
    


    I tried without success:

    a.) I added to /etc/fstab
    Code:
    none /media/psf prl_fs user,rw,exec,noatime,share,context=system_u:object_r:removable_t:s0,nofail 0 0 
    b.) and tried things like
    Code:
    sudo mount -v -t prl_fs -o sync,nodev,share,nofail,exec Home /media/psf/Home
    c.) I could not find information on the prl_fs system, e.g. prlfsmountd --help or man pages

    Any help and suggestions are highly recommended.
    Dietrich
     
  2. (GalaxyMaster)

    (GalaxyMaster) Kilo Poster

    Messages:
    54
    @DietrichL3, you are raising an interesting challenge! I never had any need to execute anything from a shared folder before, so I did not stumble upon this. The root cause is some missing support in the prl_fs module:
    Code:
    [root@archlinux ~]# mount | fgrep /Home
    Home on /mnt/psf/Home type prl_fs (rw,nosuid,nodev,noatime,sync,ttl=300,share)
    [root@archlinux ~]# ls -ld /mnt/psf/Home/execution-test.sh 
    -rwx------ 1 root root 45 Apr  1 19:25 /mnt/psf/Home/execution-test.sh
    [root@archlinux ~]# /mnt/psf/Home/execution-test.sh 
    -bash: /mnt/psf/Home/execution-test.sh: /bin/bash: bad interpreter: Invalid argument
    [root@archlinux ~]# dmesg | tail -1
    [182028.716077] kernel read not supported for file /execution-test.sh (pid: 263215 comm: bash)
    [root@archlinux ~]#
    
    Will investigate whether I can quickly fix this in the source code for prl_fs, but do not promise anything :)
     
  3. (GalaxyMaster)

    (GalaxyMaster) Kilo Poster

    Messages:
    54
    Nah, I am not going to do it now (since I don't have a need right now and the work requires to migrate the current module from `file_ops->read()` to `file_ops->read_iter()` -- this is a lot, like re-doing the entire input/output logic of the module). I guess, with the next major kernel version I will be forced to do that, since the `file_ops->read()` is going to be phased out (none of the kernel native filesystems implement it anymore), but it is in the future.

    Meanwhile, if you want to execute scripts from the shared folder, just use `bash /mnt/psf/path_to_your_script.sh`, which should work since it will open the file in the user space and not in the kernel space.
     
  4. MikhailM3

    MikhailM3 Bit Poster

    Messages:
    1
    I faced the same issue, and managed to workaround it by implementing read_iter and write_iter via existing read/write calls. It is suboptimal, as it basically takes iovec, copies to temp buffer and passes to read/write calls, and it would be really good to have pfs native support for read_iter/write_iter.

    Code:
    From 0a9f08ed3aed64ef14097f3e18ad8641b62ef1d7 Mon Sep 17 00:00:00 2001
    From: Mikhail Malygin <m.malygin@yadro.com>
    Date: Thu, 25 Mar 2021 19:30:04 +0300
    Subject: [PATCH] Implement prlfs_write_iter and prlfs_read_iter functions on
     top of prlfs_write and prlfs_read
    
    ---
     .../SharedFolders/Guest/Linux/prl_fs/file.c   | 100 +++++++++++++++++-
     1 file changed, 96 insertions(+), 4 deletions(-)
    
    diff --git a/prl_fs/SharedFolders/Guest/Linux/prl_fs/file.c b/prl_fs/SharedFolders/Guest/Linux/prl_fs/file.c
    index e779cf7..48537dc 100644
    --- a/prl_fs/SharedFolders/Guest/Linux/prl_fs/file.c
    +++ b/prl_fs/SharedFolders/Guest/Linux/prl_fs/file.c
    @@ -427,7 +427,7 @@ static ssize_t prlfs_read(struct file *filp, char *buf, size_t size,
         struct dentry *dentry = FILE_DENTRY(filp);
         struct inode *inode = dentry->d_inode;
    
    -    return prlfs_rw(inode, buf, size, off, 0, 1, TG_REQ_COMMON);
    +    return prlfs_rw(inode, buf, size, off, 0, 0, TG_REQ_COMMON);
     }
    
     static ssize_t prlfs_write(struct file *filp, const char *buf, size_t size,
    @@ -445,7 +445,7 @@ static ssize_t prlfs_write(struct file *filp, const char *buf, size_t size,
             real_off = *off;
    
         prlfs_inode_lock(inode);
    -    ret = prlfs_rw(inode, (char *)buf, size, &real_off, 1, 1, TG_REQ_COMMON);
    +    ret = prlfs_rw(inode, (char *)buf, size, &real_off, 1, 0, TG_REQ_COMMON);
         dentry->d_time = 0;
         if (ret < 0)
             goto out;
    @@ -462,6 +462,98 @@ out:
         return ret;
     }
    
    +static ssize_t prlfs_read_iter(struct kiocb *iocb, struct iov_iter *iter)
    +{
    +    ssize_t ret = 0;
    +    size_t alloc_size = 512 * 1024;
    +    size_t bytes_done = 0;
    +
    +    size_t buf_size = min_t(size_t, alloc_size, iter->count);
    +    void *buf = kzalloc(buf_size, GFP_KERNEL);
    +
    +    if(!buf) {
    +        printk("prlfs_read_iter: failed to allocate %ld bytes\n", buf_size);
    +        return -ENOMEM;
    +    }
    +
    +    DPRINTK("prlfs_read_iter: reading %ld bytes\n", iter->count);
    +
    +    while(iter->count) {
    +        size_t to_read = min_t(size_t, alloc_size, iter->count);
    +        DPRINTK("prlfs_read_iter: %ld bytes to be read from fs, remain %ld\n", to_read, iter->count);
    +
    +        ret = prlfs_read(iocb->ki_filp, buf, to_read, &iocb->ki_pos);
    +
    +        if(ret < 0) {
    +            goto err;
    +        }
    +
    +        ret = copy_to_iter(buf, ret, iter);
    +
    +        DPRINTK("prlfs_read_iter: %ld bytes copied to iter\n", ret);
    +
    +        bytes_done += ret;
    +
    +        if (ret == 0) {
    +            break;
    +        }
    +    }
    +
    +    DPRINTK("prlfs_read_iter: %ld bytes read\n", bytes_done);
    +
    +
    +    kfree(buf);
    +    return bytes_done;
    +
    +err:
    +    kfree(buf);
    +    return ret;
    +}
    +
    +static ssize_t prlfs_write_iter(struct kiocb *iocb, struct iov_iter *iter)
    +{
    +    ssize_t ret = 0;
    +    size_t alloc_size = 512 * 1024;
    +    size_t bytes_done = 0;
    +
    +    size_t buf_size = min_t(size_t, alloc_size, iter->count);
    +    void *buf = kzalloc(buf_size, GFP_KERNEL);
    +
    +    if(!buf) {
    +        printk("prlfs_write_iter: failed to allocate %ld bytes\n", buf_size);
    +        return -ENOMEM;
    +    }
    +
    +    while(iter->count) {
    +        size_t bytes = copy_from_iter(buf, min_t(ssize_t, buf_size, iter->count), iter);
    +        size_t written = 0;
    +
    +        while(written < bytes) {
    +            DPRINTK("prlfs_write_iter: %ld bytes to be written to fs", bytes);
    +
    +            ret = prlfs_write(iocb->ki_filp, buf + written, bytes - written, &iocb->ki_pos);
    +
    +            if(ret < 0) {
    +                goto err;
    +            }
    +
    +            written += ret;
    +            bytes_done += ret;
    +        }
    +
    +        if (ret == 0) {
    +            break;
    +        }
    +    }
    +
    +    kfree(buf);
    +    return bytes_done;
    +
    +err:
    +    kfree(buf);
    +    return ret;
    +}
    +
     #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
     #ifdef PRL_SIMPLE_SYNC_FILE
     int simple_sync_file(struct file *filp, struct dentry *dentry, int datasync)
    @@ -473,8 +565,8 @@ int simple_sync_file(struct file *filp, struct dentry *dentry, int datasync)
    
     struct file_operations prlfs_file_fops = {
         .open        = prlfs_open,
    -    .read           = prlfs_read,
    -    .write        = prlfs_write,
    +    .read_iter    = prlfs_read_iter,
    +    .write_iter = prlfs_write_iter,
         .llseek         = generic_file_llseek,
         .release    = prlfs_release,
         .mmap        = generic_file_mmap,
    --
    2.24.3 (Apple Git-128)
    
     
  5. (GalaxyMaster)

    (GalaxyMaster) Kilo Poster

    Messages:
    54
    Thanks for sharing, I really appreciate this! I expect that soon we will face a situation when kernel moves on to use iterators only in this space and your patch would save me a lot of time :) (unless Parallels updates their tools to be more aligned with modern kernels).

    P.S. It would be so much easier if they pushed their modules upstream and made their guest tools open source :)))) Well, I am dreaming, of course :)
     
  6. (GalaxyMaster)

    (GalaxyMaster) Kilo Poster

    Messages:
    54
    @MikhailM3 , I manually applied your patch to the latest Parallel Tools (16.5.0), since it was not applying cleanly. I've also fixed a missing header, so the attached patch can be cleanly applied to the latest tools and works like a charm. Thank you!
    Code:
    [galaxy@archlinux ~]$ fgrep /mnt/psf/Home /proc/mounts
    Home /mnt/psf/Home prl_fs rw,sync,nosuid,nodev,noatime,ttl=300,share 0 0
    [galaxy@archlinux ~]$ /mnt/psf/Home/execution-test.sh
    Hello, Parallels forum!
    [galaxy@archlinux ~]$
     

    Attached Files:

    DietrichL3 likes this.
  7. DietrichL3

    DietrichL3 Bit Poster

    Messages:
    5
    Dear MikhailM3,
    Dear GalaxyMaster,

    I must say I'm totally impressed with the solution and your in-depth understanding of the kernel. You must really understand what is going on in there.....
    I tried to apply this patch to my machine, but it did not work. As a result, I returned to an older kernel, since I'm executing all the time scripts from shared folders.

    Kind regards
    Dietrich
     

Share This Page