Esempio n. 1
0
def test_file_o_direct():
    # note:
    #   - `O_DIRECT` does not work if the file path is in memory, like "/dev/shm" or "/tmp"
    #   - currently only `MAP_PRIVATE` works with `io_uring_register_buffers`, `MAP_SHARED` will be fixed soon!

    ring = io_uring()
    cqes = io_uring_cqes()

    if skip_os('5.14'):  # was a bug < 5.14
        read = mmap(-1, PAGESIZE, flags=MAP_PRIVATE)
        write = mmap(-1, PAGESIZE, flags=MAP_PRIVATE)
    else:
        read = mmap(-1, PAGESIZE)  # MAP_SHARED
        write = mmap(-1, PAGESIZE)

    write[0:11] = b'hello world'
    iov = iovec(write, read)
    try:
        assert io_uring_queue_init(2, ring, 0) == 0
        assert io_uring_register_buffers(ring, iov, len(iov)) == 0

        # open - create local testing file.
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_openat(sqe, AT_FDCWD, b'.',
                             O_TMPFILE | O_RDWR | O_DIRECT, 0o700)
        fd = submit_wait_result(ring, cqes)

        # write
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_write_fixed(sqe, fd, iov[0].iov_base, iov[0].iov_len, 0,
                                  0)
        assert submit_wait_result(ring, cqes) == PAGESIZE

        # read
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_read_fixed(sqe, fd, iov[1].iov_base, iov[1].iov_len, 0,
                                 1)
        assert submit_wait_result(ring, cqes) == PAGESIZE

        # confirm
        assert read[:20] == write[:20]

        # close
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_close(sqe, fd)
        assert submit_wait_result(ring, cqes) == 0

    finally:
        read.close()
        write.close()
        io_uring_queue_exit(ring)
Esempio n. 2
0
def test_register_fd_close():
    ring = io_uring()
    cqes = io_uring_cqes()
    write = bytearray(b'hello world')
    read = bytearray(11)
    iov = iovec(write, read)
    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        # open - create local testing file.
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_openat(sqe, AT_FDCWD, b'.', O_TMPFILE | O_RDWR, 0o700)
        fd = submit_wait_result(ring, cqes)

        # register `fds`
        fds = files(fd)  # `int[fd]`
        index = 0
        assert io_uring_register_files(ring, fds, len(fds)) == 0

        # close - right away after registering fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_close(sqe, fd)
        assert submit_wait_result(ring, cqes) == 0

        # write - using registered file index and closed fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_write(sqe, index, iov[0].iov_base, iov[0].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # read - using registered file index and closed fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_read(sqe, index, iov[1].iov_base, iov[1].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # confirm
        assert write == read

        # unregister - index
        fds = files(-1)
        assert io_uring_register_files_update(ring, index, fds, 1) == 1

        # re-read - should not be able to since index was unregistered
        with raises(OSError):  # [Errno 9] Bad file descriptor
            sqe = io_uring_get_sqe(ring)
            io_uring_prep_read(sqe, index, iov[1].iov_base, iov[1].iov_len, 0)
            sqe.flags |= IOSQE_FIXED_FILE
            assert submit_wait_result(ring, cqes) == 11
    finally:
        io_uring_queue_exit(ring)
Esempio n. 3
0
def test_register_file_update():
    ring = io_uring()
    cqes = io_uring_cqes()
    write = bytearray(b'hello world')
    read = bytearray(11)
    iov = iovec(write, read)
    fds = files(-1, -1, -1, -1)  # prep 4 fd spots
    index = 2  # only use index ``2`` of the `fds`
    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        # register 4 `fds`
        assert io_uring_register_files(ring, fds, len(fds)) == 0

        # open - create local testing file.
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_openat(sqe, AT_FDCWD, b'.', O_TMPFILE | O_RDWR, 0o700)
        fd = submit_wait_result(ring, cqes)
        fds[index] = fd

        fd2 = files(fd)  # `int[fd]`
        # register - update only the index ``2`` value
        assert io_uring_register_files_update(ring, index, fd2, 1) == 1

        # close
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_close(sqe, fds[index])
        assert submit_wait_result(ring, cqes) == 0

        # write - using registered file index vs fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_write(sqe, index, iov[0].iov_base, iov[0].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # read - using registered file index vs fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_read(sqe, index, iov[1].iov_base, iov[1].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # confirm
        assert write == read

        # unregister
        assert io_uring_unregister_files(ring) == 0
    finally:
        io_uring_queue_exit(ring)
Esempio n. 4
0
def test_register_file():
    ring = io_uring()
    cqes = io_uring_cqes()
    write = bytearray(b'hello world')
    read = bytearray(11)
    iov = iovec(write, read)
    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        # open - create local testing file.
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_openat(sqe, AT_FDCWD, b'.', O_TMPFILE | O_RDWR, 0o700)
        fd = submit_wait_result(ring, cqes)

        # register `fds`
        fds = files(fd)  # `int[fd]`
        index = 0
        assert io_uring_register_files(ring, fds, len(fds)) == 0

        # close
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_close(sqe, fd)
        assert submit_wait_result(ring, cqes) == 0

        # write - using registered file index vs fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_write(sqe, index, iov[0].iov_base, iov[0].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # read - using registered file index vs fd
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_read(sqe, index, iov[1].iov_base, iov[1].iov_len, 0)
        sqe.flags |= IOSQE_FIXED_FILE
        assert submit_wait_result(ring, cqes) == 11

        # confirm
        assert write == read
    finally:
        # note: let exit also unregister fds
        io_uring_queue_exit(ring)
Esempio n. 5
0
def test_multiple_register_fd_mix(tmpdir):
    ring = io_uring()
    cqes = io_uring_cqes()
    loop = randint(2, 5)
    data = b'hello world'
    write = [bytearray(data) for _ in range(loop)]
    iov = iovec(*write)
    fds = files(-1 for _ in range(loop))  # prep fds
    try:
        assert io_uring_queue_init(2, ring, 0) == 0
        # initialize register
        assert io_uring_register_files(ring, fds, len(fds)) == 0

        for index in range(loop):  # index = 0, 1, ...
            path = join(tmpdir, f'register-fd-mix-{index}.txt').encode()
            # open
            sqe = io_uring_get_sqe(ring)
            io_uring_prep_openat(sqe, AT_FDCWD, path, O_CREAT | O_RDWR, 0o700)
            fd = submit_wait_result(ring, cqes)

            # register update
            if index == 1:  # skip registering middle one!
                fd1 = fd
            else:
                fds = files(fd)
                assert io_uring_register_files_update(ring, index, fds, 1) == 1

                # close registered fd only
                sqe = io_uring_get_sqe(ring)
                io_uring_prep_close(sqe, fd)
                assert submit_wait_result(ring, cqes) == 0

        # write
        for index in range(loop):
            sqe = io_uring_get_sqe(ring)
            if index == 1:  # write using fd
                io_uring_prep_write(sqe, fd1, iov[index].iov_base, iov[index].iov_len, 0)
            else:  # write using registered file index
                io_uring_prep_write(sqe, index, iov[index].iov_base, iov[index].iov_len, 0)
                sqe.flags |= IOSQE_FIXED_FILE
            assert submit_wait_result(ring, cqes) == 11

        # read
        for index in range(loop):
            path = join(tmpdir, f'register-fd-mix-{index}.txt').encode()
            stat = statx()
            sqe = io_uring_get_sqe(ring)
            io_uring_prep_statx(sqe, AT_FDCWD, path, 0, 0, stat)
            assert submit_wait_result(ring, cqes) == 0
            length = stat[0].stx_size  # get written file size
            # note: even though size is known, get it using statx

            read = bytearray(length)
            buffer = from_buffer(read)

            sqe = io_uring_get_sqe(ring)
            if index == 1:
                io_uring_prep_read(sqe, fd1, buffer, length, 0)
            else:  # read using registered file index
                io_uring_prep_read(sqe, index, buffer, length, 0)
                sqe.flags |= IOSQE_FIXED_FILE
            assert submit_wait_result(ring, cqes) == 11
            assert read == data

        # close
        for index in range(loop):
            if index == 1:
                sqe = io_uring_get_sqe(ring)
                io_uring_prep_close(sqe, fd1)
                assert submit_wait_result(ring, cqes) == 0
            else:  # unregister file index
                fds = files(-1)
                assert io_uring_register_files_update(ring, index, fds, 1) == 1
    finally:
        io_uring_queue_exit(ring)
Esempio n. 6
0
def open_file(ring, cqes, file_path, cred_id):
    sqe = io_uring_get_sqe(ring)
    io_uring_prep_openat(sqe, AT_FDCWD, file_path, O_RDONLY, 0)
    if cred_id is not None:
        sqe.personality = cred_id
    return submit_wait_result(ring, cqes)  # fd
Esempio n. 7
0
def test_personality(tmpdir):
    # note: `sqe.personality` has limited use-case like its restricts to opening `fd`
    #       but not for read, write, close, ...

    ring = io_uring()
    cqes = io_uring_cqes()
    file_path = join(tmpdir, 'test_personality_root_file.txt').encode()
    try:
        assert io_uring_queue_init(2, ring, 0) == 0

        # create & open file only root can access!
        sqe = io_uring_get_sqe(ring)
        io_uring_prep_openat(sqe, AT_FDCWD, file_path, O_CREAT, 0o700)
        fd = submit_wait_result(ring, cqes)
        close_file(ring, cqes, fd)

        root_cred_id = io_uring_register_personality(ring)
        assert root_cred_id == 1

        # normal "user"
        setegid(1000)
        seteuid(1000)

        user_cred_id = io_uring_register_personality(ring)
        assert user_cred_id == 2

        # try to open root file as normal user.
        with raises(PermissionError):
            open_file(ring, cqes, file_path, None)

        # bad personality
        with raises(OSError):  # Invalid argument
            open_file(ring, cqes, file_path, 2)

        # what about default `0` for personality
        with raises(PermissionError):
            open_file(ring, cqes, file_path, 0)

        # try again to open file with root credential
        fd = open_file(ring, cqes, file_path, root_cred_id)
        close_file(ring, cqes, fd)

        # "root" again
        setegid(0)
        seteuid(0)

        # try again to open file with root credential
        fd = open_file(ring, cqes, file_path, root_cred_id)
        close_file(ring, cqes, fd)

        # try again to open file with no credential
        fd = open_file(ring, cqes, file_path, None)
        close_file(ring, cqes, fd)

        # try again to open file with "user" credential
        with raises(PermissionError):
            open_file(ring, cqes, file_path, user_cred_id)

        # "user" again
        setegid(1000)
        seteuid(1000)

        # try to unregister "root" personality
        assert io_uring_unregister_personality(ring, root_cred_id) == 0

        # try to unregister "user" personality
        assert io_uring_unregister_personality(ring, user_cred_id) == 0

        # try to open file with unregistered old "root" credential
        with raises(OSError):  # Invalid argument
            open_file(ring, cqes, file_path, root_cred_id)

    finally:
        # make sure its "root" again to allow proper cleanup
        seteuid(0)
        setegid(0)

        if exists(file_path):
            unlink(file_path)

        io_uring_queue_exit(ring)
Esempio n. 8
0
 def submit_open_entry(self, fpath, flags, mode, dir_fd):
     sqe = self._get_sqe()
     path = os.path.abspath(fpath).encode()
     liburing.io_uring_prep_openat(sqe, dir_fd, path, flags, mode)
     return self._submit(RequestType.OPEN, sqe, path)