wasmerio / wasmer

🚀 The leading Wasm Runtime supporting WASIX, WASI and Emscripten
https://wasmer.io
MIT License
18.63k stars 798 forks source link

Permission denied? #4245

Open orangeC23 opened 1 year ago

orangeC23 commented 1 year ago

Describe the bug

Using clang to compile the following C file into Wasm binaries, and execute the Wasm binaries. However, wasmer prints different result.

Steps to reproduce

The c file is :

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>

int main() {
    const char* file_name = "Data/hello.txt";
    int open_style= O_RDONLY;
    int fd = get_fd(file_name, open_style);
    snapshot(fd);
    return 0;
}

int get_fd(const char* file_name, int open_style){
    // Open a file for reading
    int fd = open(file_name, open_style);
    if (fd == -1) {
        perror("Failed to open the file");
        return 1;
    }

    return fd;
}

int snapshot(int myfd){   
    struct stat file_info;
    if (fstat(myfd, &file_info) == -1) {
        perror("Error getting file attributes");
        close(myfd);
        return 1;
    }

    printf("File Size: %lld bytes\\n", (long long)file_info.st_size);
    printf("File Permissions: %o\\n", file_info.st_mode & ~S_IFMT); 
    printf("File Owner UID: %d\\n", file_info.st_uid); 
    printf("File Group GID: %d\\n", file_info.st_gid);

    off_t cur_offset = lseek(myfd, 0, SEEK_CUR);
    if (cur_offset == -1) {
        perror("Error getting current offset");
    }
    printf("Current offset: %lld\\n", (long long)cur_offset);

    if (close(myfd) == -1) {
        perror("Error closing file");
        return 1;
    }
}

(1)compile it into wasm ./wasi-sdk-16.0/bin/clang --target=wasm32-unkown-wasi --sysroot=./wasi-sdk-16.0/share/wasi-sysroot open.c -o open.wasm (2)exeute open.wasm ./wasmer-linux-amd64/bin/wasmer run --dir=./Data open.wasm ./wasmtime run --dir=./Data open.wasm ./wasm-micro-runtime-WAMR-05-18-2022/product-mini/platforms/linux/build/iwasm --dir=./Data open.wasm ./wasmedge0.9/bin/wasmedge --dir=./Data open.wasm The permission of Data/hello.txt is 0700, user1 create the Data/hello.txt file and user1 execute the Wasm file.

Expected behavior

wasmtime, WAMR and WasmEdge prints:

File Size: 30 bytes\nFile Permissions: 0\nFile Owner UID: 0\nFile Group GID: 0\nCurrent offset: 0\n

Actual behavior

wasmer prints:

./wasmer-linux-amd64/bin/wasmer: Permission denied
Michael-F-Bryan commented 1 year ago

This sounds like an issue with wasmer-wasix's permission handling. Possibly inside WasiFS.

orangeC23 commented 12 months ago

Maybe this bug is also the same reason about permission. Using 0500 to execute is denied.

Steps to reproduce

The c file is :

#include <stdio.h>
#include <stdlib.h>
#include <sys/uio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>

int main() {
    const char* file_name = "Data/hello.txt";
    int open_style= O_RDONLY;
    int fd = get_fd(file_name, open_style);
    fd_readrOgoSTjbzI(fd);
    snapshot(fd);
    return 0;
}

int fd_readrOgoSTjbzI(int fd) {
    off_t offset_value = 0;
    int buffer_size = 42;
    return fd_read(fd, offset_value, buffer_size);
}

int get_fd(const char* file_name, int open_style){
    int fd = open(file_name, open_style);
    if (fd == -1) {
        perror("Failed to open the file");
        return 1;
    }

    return fd;
}

int fd_read(int fd, off_t offset_value, int buffer_size) {
    printf("Enter fd_read\n");

    struct iovec iov[1]; 
    char buf1[buffer_size]; 
    ssize_t bytesRead;

    off_t new_offset = offset_value; 

    if (lseek(fd, new_offset, SEEK_SET) == -1) {
        perror("Error setting new offset");
        close(fd);
        return 1;
    }

    off_t current_offset = lseek(fd, 0, SEEK_CUR);
    if (current_offset == -1) {
        perror("Error getting current offset");
    }
    printf("Current offset: %lld\n", (long long)current_offset);

    iov[0].iov_base = buf1;
    iov[0].iov_len = sizeof(buf1);

    bytesRead = readv(fd, iov, 1);

    if (bytesRead == -1) {
        perror("readv");
        exit(EXIT_FAILURE);
    } else if (bytesRead == 0) {
        printf("End of file reached.\n");
    } else {
        printf("Read %zd bytes from file descriptor.\n", bytesRead);
        printf("Data in buf1: %.*s\n", (int)iov[0].iov_len, (char*)iov[0].iov_base);
    }

    printf("Leave fd_read\n");
    return fd;
}

int snapshot(int myfd){   
    printf("Enter snapshot\n");
    struct stat file_info;
    if (fstat(myfd, &file_info) == -1) {
        perror("Error getting file attributes");
        close(myfd);
        return 1;
    }

    printf("File Size: %lld bytes \n", (long long)file_info.st_size);

    off_t cur_offset = lseek(myfd, 0, SEEK_CUR);
    if (cur_offset == -1) {
        perror("Error getting current offset");
    }
    printf("Current offset: %lld \n", (long long)cur_offset);

    if (close(myfd) == -1) {
        perror("Error closing file");
        return 1;
    }

    printf("Leave snapshot\n");
}

(1)compile it into wasm ./wasi-sdk-16.0/bin/clang --target=wasm32-unkown-wasi --sysroot=./wasi-sdk-16.0/share/wasi-sysroot read.c -o read.wasm (2)The permission of Data/hello.txt is 0500, user1 create the Data/hello.txt file and user1 execute the Wasm file.

Expected behavior

wasmtime, WAMR and WasmEdge prints:

Enter fd_read
Current offset: 0
Read 30 bytes from file descriptor.
Data in buf1: Hello,test!
line1
line2
Bye!

Leave fd_read
Enter snapshot
File Size: 30 bytes 
Current offset: 30 
Leave snapshot

Actual behavior

wasmer prints:

Failed to open the file: Operation not permitted
Error setting new offset: Permission denied
Error getting file attributes: Bad file descriptor
orangeC23 commented 10 months ago

We simpltfied the test case: test-c.txt

When the permision is 0400, other runtime could open the file whether wasmer could not. wasmer prints:Operation not permitted

We examined the source code of Wasmer and identified a potential issue in lib/wasix/src/syscalls/wasi/path_open.rs. In this file, the value of working_dir_rights_inheriting is directly assigned to adjusted_rights. As long as adjusted_rights contains Rights::FD_WRITE, write_permission becomes true. The write in target_rights is assigned the value of write_permission, and similarly, write in parent_rights is assigned the value of write in target_rights. Minimum Rights are assigned using parent_rights, where write is also true. The open_options are set using minimum_rights, where write is again true. At this point, the file permission is set to 0400, granting only read access, resulting in a permission denied error. However, this test case only requires read permission to run, which is the approach taken by other runtimes.

Therefore, if my understanding of the code is correct, could Wasmer have a small bug? Perhaps Wasmer is demanding some additional permissions at this point, leading to a permission denied error.

We printed the value of working_dir_rights_inheriting, which initially is assigned many permissions: FD_DATASYNC, FD_READ, FD_SEEK, FD_FDSTAT_SET_FLAGS, FD_SYNC, FD_TELL, FD_WRITE, FD_ADVISE, FD_ALLOCATE, PATH_CREATE_DIRECTORY, PATH_CREATE_FILE, PATH_LINK_SOURCE, PATH_LINK_TARGET, PATH_OPEN, FD_READDIR, PATH_READLINK, PATH_RENAME_SOURCE, PATH_RENAME_TARGET, PATH_FILESTAT_GET, PATH_FILESTAT_SET_SIZE, PATH_FILESTAT_SET_TIMES, FD_FILESTAT_GET, FD_FILESTAT_SET_SIZE, FD_FILESTAT_SET_TIMES, PATH_SYMLINK, PATH_REMOVE_DIRECTORY, PATH_UNLINK_FILE, POLL_FD_READWRITE, SOCK_SHUTDOWN. Is it reasonable to grant so many permissions to working_dir_rights_inheriting initially? I'm not entirely sure.

matsbror commented 10 months ago

I have the same issue.