Skip to content

Commit

Permalink
Add ioctl to the Gramine test device
Browse files Browse the repository at this point in the history
New IOCTLs (simple manipulations on a byte array):
- GRAMINE_TEST_DEV_IOCTL_REWIND
- GRAMINE_TEST_DEV_IOCTL_WRITE
- GRAMINE_TEST_DEV_IOCTL_READ
- GRAMINE_TEST_DEV_IOCTL_GETSIZE
- GRAMINE_TEST_DEV_IOCTL_CLEAR
- GRAMINE_TEST_DEV_IOCTL_REPLACE_ARR
- GRAMINE_TEST_DEV_IOCTL_REPLACE_LIST

Signed-off-by: Dmitrii Kuvaiskii <[email protected]>
  • Loading branch information
dimakuv committed Jul 25, 2022
1 parent 738b9c8 commit 20eea9c
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 11 deletions.
31 changes: 21 additions & 10 deletions gramine-device-testing-module/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,25 @@ all required functionality (e.g shared untrusted memory and ioctl syscall).
Features
========

This driver implements a custom character device, which allows for simple string
manipulations. Each open file handle is associated with a context holding all
necessary data, and allows for the following operations:
This driver implements a custom character device, which allows for simple byte
array manipulations. Each open file handle is associated with a context holding
all necessary data, and allows for the following operations:

- `open` - Create a string instance.
- `write` - Write data to the string at the current offset. If some data was
present at this offset, it's overwritten. The string is automatically
extended if needed.
- `read` - Read that from the string.
- `llseek` - Change the current offset in the string.
- `release` - Releases the string instance.
- `open` - Create a byte array instance.
- `write` - Write data to the byte array at the current offset. If some data
was present at this offset, it's overwritten. The byte array is
automatically extended if needed.
- `read` - Read data from the byte array.
- `llseek` - Change the current offset in the byte array.
- `release` - Releases the byte array instance.
- `unlocked_ioctl` - Perform one of the following IOCTLs:
- `GRAMINE_TEST_DEV_IOCTL_REWIND` - same as `llseek(filp, 0, SEEK_SET)`.
- `GRAMINE_TEST_DEV_IOCTL_WRITE` - same as `write`.
- `GRAMINE_TEST_DEV_IOCTL_READ` - same as `read`.
- `GRAMINE_TEST_DEV_IOCTL_GETSIZE` - Returns size of the byte array.
- `GRAMINE_TEST_DEV_IOCTL_CLEAR` - Frees the byte array.
- `GRAMINE_TEST_DEV_IOCTL_REPLACE_ARR` - Replaces specified characters in
the byte array; character replacements are passed as an array.
- `GRAMINE_TEST_DEV_IOCTL_REPLACE_LIST` - same as
`GRAMINE_TEST_DEV_IOCTL_REPLACE_ARR` but character replacements are passed
as a NULL-terminated list.
49 changes: 49 additions & 0 deletions gramine-device-testing-module/gramine_test_dev_ioctl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once

#include <linux/ioctl.h>

struct gramine_test_dev_ioctl_write {
size_t buf_size; /* in */
const char __user* buf; /* in */
loff_t off; /* in/out -- updated after write */
ssize_t copied; /* out -- how many bytes were actually written */
};

struct gramine_test_dev_ioctl_read {
size_t buf_size; /* in */
char __user* buf; /* out */
loff_t off; /* in/out -- updated after read */
ssize_t copied; /* out -- how many bytes were actually read */
};

struct gramine_test_dev_ioctl_replace_char {
char src; /* in */
char dst; /* in */
char pad[6];
};

struct gramine_test_dev_ioctl_replace_arr {
/* array of replacements, e.g. replacements_cnt == 2 and [`l` -> `$`, `o` -> `0`] */
size_t replacements_cnt;
struct gramine_test_dev_ioctl_replace_char __user* replacements_arr;
};

struct gramine_test_dev_ioctl_replace_list {
/* list of replacements, e.g. [`l` -> `$`, next points to `o` -> `0`, next points to NULL] */
struct gramine_test_dev_ioctl_replace_char replacement;
struct gramine_test_dev_ioctl_replace_list __user* next;
};

#define GRAMINE_TEST_DEV_IOCTL_BASE 0x81

#define GRAMINE_TEST_DEV_IOCTL_REWIND _IO(GRAMINE_TEST_DEV_IOCTL_BASE, 0x00)
#define GRAMINE_TEST_DEV_IOCTL_WRITE _IOWR(GRAMINE_TEST_DEV_IOCTL_BASE, 0x01, \
struct gramine_test_dev_ioctl_write)
#define GRAMINE_TEST_DEV_IOCTL_READ _IOWR(GRAMINE_TEST_DEV_IOCTL_BASE, 0x02, \
struct gramine_test_dev_ioctl_read)
#define GRAMINE_TEST_DEV_IOCTL_GETSIZE _IO(GRAMINE_TEST_DEV_IOCTL_BASE, 0x03)
#define GRAMINE_TEST_DEV_IOCTL_CLEAR _IO(GRAMINE_TEST_DEV_IOCTL_BASE, 0x04)
#define GRAMINE_TEST_DEV_IOCTL_REPLACE_ARR _IOW(GRAMINE_TEST_DEV_IOCTL_BASE, 0x05, \
struct gramine_test_dev_ioctl_replace_arr)
#define GRAMINE_TEST_DEV_IOCTL_REPLACE_LIST _IOW(GRAMINE_TEST_DEV_IOCTL_BASE, 0x06, \
struct gramine_test_dev_ioctl_replace_list)
112 changes: 111 additions & 1 deletion gramine-device-testing-module/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <linux/module.h>
#include <linux/slab.h>

#include "gramine_test_dev_ioctl.h"

// TODO: add locking

MODULE_AUTHOR("Gramine Authors");
Expand All @@ -19,6 +21,8 @@ MODULE_DESCRIPTION("Dummy module just for testing purposes");
#define GRAMINE_TEST_DEV_MINOR_NUMS 1
#define GRAMINE_TEST_DEV_MAX_SIZE (0x100 * PAGE_SIZE)

#define LIST_ITEMS_MAX 128

struct gramine_test_dev_data {
size_t size;
char* buf;
Expand All @@ -29,6 +33,14 @@ static dev_t dev_num = 0;
struct cdev cdev;
struct device* device = NULL;

static void replace_all_occurences(struct gramine_test_dev_data* data, char src, char dst) {
size_t idx;
for (idx = 0; idx < data->size; idx++) {
if (data->buf[idx] == src)
data->buf[idx] = dst;
}
}

static int gramine_test_dev_open(struct inode* inode, struct file* filp) {
struct gramine_test_dev_data* data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
Expand Down Expand Up @@ -110,11 +122,109 @@ static ssize_t gramine_test_dev_read(struct file* filp, char __user* buf, size_t
return copy_size;
}

static int gramine_test_dev_replace_arr(struct gramine_test_dev_data* data,
void __user* argp_user) {
size_t i;
struct gramine_test_dev_ioctl_replace_arr arg;

if (copy_from_user(&arg, argp_user, sizeof(arg))) {
return -EFAULT;
}

for (i = 0; i < arg.replacements_cnt; i++) {
struct gramine_test_dev_ioctl_replace_char replace_char;
if (copy_from_user(&replace_char, &arg.replacements_arr[i], sizeof(replace_char))) {
return -EFAULT;
}
replace_all_occurences(data, replace_char.src, replace_char.dst);
}

return 0;
}

static int gramine_test_dev_replace_list(struct gramine_test_dev_data* data,
void __user* argp_user) {
size_t list_items_cnt = 0;
struct gramine_test_dev_ioctl_replace_list __user* list_item_user = argp_user;

do {
struct gramine_test_dev_ioctl_replace_list list_item;
if (list_items_cnt++ > LIST_ITEMS_MAX) {
return -ELOOP;
}
if (copy_from_user(&list_item, list_item_user, sizeof(list_item))) {
return -EFAULT;
}
replace_all_occurences(data, list_item.replacement.src, list_item.replacement.dst);
list_item_user = list_item.next;
} while (list_item_user);

return 0;
}

static ssize_t gramine_test_dev_ioctl(struct file *filp, unsigned int cmd, unsigned long argp) {
struct gramine_test_dev_data* data = filp->private_data;
void __user* argp_user = (void __user*)argp;

switch (cmd) {
case GRAMINE_TEST_DEV_IOCTL_REWIND:
return default_llseek(filp, /*offset=0*/0, SEEK_SET);
case GRAMINE_TEST_DEV_IOCTL_WRITE: {
ssize_t copied;
struct gramine_test_dev_ioctl_write arg;
if (copy_from_user(&arg, argp_user, sizeof(arg))) {
return -EFAULT;
}
copied = gramine_test_dev_write(filp, arg.buf, arg.buf_size, &arg.off);
if (copied < 0) {
return copied;
}
arg.copied = copied;
if (copy_to_user(argp_user, &arg, sizeof(arg))) {
return -EFAULT;
}
return 0;
}
case GRAMINE_TEST_DEV_IOCTL_READ: {
ssize_t copied;
struct gramine_test_dev_ioctl_read arg;
if (copy_from_user(&arg, argp_user, sizeof(arg))) {
return -EFAULT;
}
copied = gramine_test_dev_read(filp, arg.buf, arg.buf_size, &arg.off);
if (copied < 0) {
return copied;
}
arg.copied = copied;
if (copy_to_user(argp_user, &arg, sizeof(arg))) {
return -EFAULT;
}
return 0;
}
case GRAMINE_TEST_DEV_IOCTL_GETSIZE:
return (ssize_t)data->size;
case GRAMINE_TEST_DEV_IOCTL_CLEAR:
kfree(data->buf);
data->size = 0;
data->buf = NULL;
return 0;
case GRAMINE_TEST_DEV_IOCTL_REPLACE_ARR:
return gramine_test_dev_replace_arr(data, argp_user);
case GRAMINE_TEST_DEV_IOCTL_REPLACE_LIST:
return gramine_test_dev_replace_list(data, argp_user);
default:
return -EINVAL;
}

return 0;
}

static struct file_operations fops = {
.owner = THIS_MODULE,
.llseek = default_llseek,
.read = gramine_test_dev_read,
.write = gramine_test_dev_write,
.read = gramine_test_dev_read,
.unlocked_ioctl = gramine_test_dev_ioctl,
.open = gramine_test_dev_open,
.release = gramine_test_dev_release,
};
Expand Down

0 comments on commit 20eea9c

Please sign in to comment.