Skip to content

Commit

Permalink
[LibOS] Implement {,l,f}getxattr and {,l,f}listxattr
Browse files Browse the repository at this point in the history
This commit implements getxattr, lgetxattr, fgetxattr, listxattr,
llistxattr and flistxattr.

They aren't too useful because Gramine neither supports mounting files
with xattrs nor setting them, but at least it makes some programs
generate less warnings (e.g. `ls -l`).

Signed-off-by: Michał Kowalczyk <[email protected]>
  • Loading branch information
mkow committed Aug 6, 2024
1 parent a9d08fd commit 67a00de
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 53 deletions.
71 changes: 38 additions & 33 deletions Documentation/devel/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -727,40 +727,40 @@ The below list is generated from the [syscall table of Linux
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>

-`setxattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
<sup>[9a](#file-system-operations)</sup>

-`lsetxattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
<sup>[9a](#file-system-operations)</sup>

-`fsetxattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
<sup>[9a](#file-system-operations)</sup>

- `getxattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
- `getxattr()`
<sup>[9a](#file-system-operations)</sup>

- `lgetxattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
- `lgetxattr()`
<sup>[9a](#file-system-operations)</sup>

- `fgetxattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
- `fgetxattr()`
<sup>[9a](#file-system-operations)</sup>

- `listxattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
- `listxattr()`
<sup>[9a](#file-system-operations)</sup>

- `llistxattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
- `llistxattr()`
<sup>[9a](#file-system-operations)</sup>

- `flistxattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
- `flistxattr()`
<sup>[9a](#file-system-operations)</sup>

-`removexattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
<sup>[9a](#file-system-operations)</sup>

-`lremovexattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
<sup>[9a](#file-system-operations)</sup>

-`fremovexattr()`
<sup>[24](#advancedinfeasible-unimplemented-features)</sup>
<sup>[9a](#file-system-operations)</sup>

-`tkill()`
<sup>[7](#signals-and-process-state-changes)</sup>
Expand Down Expand Up @@ -2125,6 +2125,13 @@ all have hard-coded values.
Gramine currently does *not* support changing file access/modification times, via `utime()`,
`utimes()`, `futimesat()`, `utimensat()` system calls.

Mounting files and directories with extended attributes (xattr) or setting them
via `setxattr()`, `lsetxattr()`, `fsetxattr()`, `removexattr()`, `lremovexattr()`, `fremovexattr()`
is not supported.
Reading is supported (`getxattr()`, `lgetxattr()`, `fgetxattr()`, `listxattr()`, `llistxattr()`,
`flistxattr()`) but always returns no attributes (which is a correct result in our case).


<details><summary>Related system calls</summary>

-`open()`: implemented, with limitations
Expand Down Expand Up @@ -2220,6 +2227,19 @@ Gramine currently does *not* support changing file access/modification times, vi
-`futimesat()`: may be implemented in the future
-`utimensat()`: may be implemented in the future

-`getxattr()`
-`lgetxattr()`
-`fgetxattr()`
-`listxattr()`
-`llistxattr()`
-`flistxattr()`
-`removexattr()`
-`lremovexattr()`
-`fremovexattr()`
-`setxattr()`
-`lsetxattr()`
-`fsetxattr()`

</details><br />

#### File locking
Expand Down Expand Up @@ -3098,9 +3118,6 @@ codebase of Gramine minimal.
- Berkeley Packet Filters (BPF) and eBPF: `bpf()`
- Capabilities: `capget()`, `capset()`
- Execution control and debugging: `ptrace()`, `syslog()`, `perf_event_open()`, `acct()`
- Extended attributes for files and directories (xattr): `setxattr()`, `lsetxattr()`,
`fsetxattr()`, `getxattr()`, `lgetxattr()`, `fgetxattr()`, `listxattr()`, `llistxattr()`,
`flistxattr()`, `removexattr()`, `lremovexattr()`, `fremovexattr()`
- In-kernel key management (keyrings): `add_key()`, `request_key()`, `keyctl()`
- Kernel modules: `create_module()`, `init_module()`, `finit_module()`, `delete_module()`,
`query_module()`, `get_kernel_syms()`
Expand Down Expand Up @@ -3132,18 +3149,13 @@ codebase of Gramine minimal.
-`copy_file_range()`
-`create_module()`
-`delete_module()`
-`fgetxattr()`
-`finit_module()`
-`flistxattr()`
-`fremovexattr()`
-`fsconfig()`
-`fsetxattr()`
-`fsmount()`
-`fsopen()`
-`fspick()`
-`get_kernel_syms()`
-`getpmsg()`
-`getxattr()`
-`init_module()`
-`io_pgetevents()`
-`ioperm()`
Expand All @@ -3154,12 +3166,7 @@ codebase of Gramine minimal.
-`landlock_add_rule()`
-`landlock_create_ruleset()`
-`landlock_restrict_self()`
-`lgetxattr()`
-`listxattr()`
-`llistxattr()`
-`lookup_dcookie()`
-`lremovexattr()`
-`lsetxattr()`
-`modify_ldt()`
-`nfsservctl()`
-`nfsservctl()`
Expand All @@ -3178,14 +3185,12 @@ codebase of Gramine minimal.
-`quotactl_fd()`
-`readahead()`
-`reboot()`
-`removexattr()`
-`request_key()`
-`restart_syscall()`
-`rseq()`
-`seccomp()`
-`security()`
-`setns()`
-`setxattr()`
-`splice()`
-`swapoff()`
-`swapon()`
Expand Down
3 changes: 1 addition & 2 deletions libos/include/libos_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,7 @@ int check_permissions(struct libos_dentry* dent, mode_t mask);
* \param flags Lookup flags (see description below).
* \param[out] found Pointer to retrieved dentry.
*
* The caller should hold `g_dcache_lock`. If you do not already hold `g_dcache_lock`, use
* `path_lookupat` instead.
* The caller should hold `g_dcache_lock`.
*
* On success, returns 0, and puts the retrieved dentry in `*found`. The reference count of the
* dentry will be increased by one.
Expand Down
8 changes: 8 additions & 0 deletions libos/include/libos_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,14 @@ long libos_syscall_chroot(const char* filename);
long libos_syscall_sethostname(char* name, int len);
long libos_syscall_setdomainname(char* name, int len);
long libos_syscall_gettid(void);

long libos_syscall_getxattr(const char* path, const char* name, void* value, size_t value_size);
long libos_syscall_lgetxattr(const char* path, const char* name, void* value, size_t value_size);
long libos_syscall_fgetxattr(int fd, const char* name, void* value, size_t value_size);
long libos_syscall_listxattr(const char* path, char* list, size_t list_size);
long libos_syscall_llistxattr(const char* path, char* list, size_t list_size);
long libos_syscall_flistxattr(int fd, char* list, size_t list_size);

long libos_syscall_tkill(int pid, int sig);
long libos_syscall_time(time_t* tloc);
long libos_syscall_futex(int* uaddr, int op, int val, void* utime, int* uaddr2, int val3);
Expand Down
12 changes: 6 additions & 6 deletions libos/src/arch/x86_64/libos_table.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,12 @@ libos_syscall_t libos_syscall_table[LIBOS_SYSCALL_BOUND] = {
[__NR_setxattr] = (libos_syscall_t)0, // libos_syscall_setxattr
[__NR_lsetxattr] = (libos_syscall_t)0, // libos_syscall_lsetxattr
[__NR_fsetxattr] = (libos_syscall_t)0, // libos_syscall_fsetxattr
[__NR_getxattr] = (libos_syscall_t)0, // libos_syscall_getxattr
[__NR_lgetxattr] = (libos_syscall_t)0, // libos_syscall_lgetxattr
[__NR_fgetxattr] = (libos_syscall_t)0, // libos_syscall_fgetxattr
[__NR_listxattr] = (libos_syscall_t)0, // libos_syscall_listxattr
[__NR_llistxattr] = (libos_syscall_t)0, // libos_syscall_llistxattr
[__NR_flistxattr] = (libos_syscall_t)0, // libos_syscall_flistxattr
[__NR_getxattr] = (libos_syscall_t)libos_syscall_getxattr,
[__NR_lgetxattr] = (libos_syscall_t)libos_syscall_lgetxattr,
[__NR_fgetxattr] = (libos_syscall_t)libos_syscall_fgetxattr,
[__NR_listxattr] = (libos_syscall_t)libos_syscall_listxattr,
[__NR_llistxattr] = (libos_syscall_t)libos_syscall_llistxattr,
[__NR_flistxattr] = (libos_syscall_t)libos_syscall_flistxattr,
[__NR_removexattr] = (libos_syscall_t)0, // libos_syscall_removexattr
[__NR_lremovexattr] = (libos_syscall_t)0, // libos_syscall_lremovexattr
[__NR_fremovexattr] = (libos_syscall_t)0, // libos_syscall_fremovexattr
Expand Down
18 changes: 12 additions & 6 deletions libos/src/libos_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -377,12 +377,18 @@ struct parser_table {
[__NR_setxattr] = {.slow = false, .name = "setxattr", .parser = {NULL}},
[__NR_lsetxattr] = {.slow = false, .name = "lsetxattr", .parser = {NULL}},
[__NR_fsetxattr] = {.slow = false, .name = "fsetxattr", .parser = {NULL}},
[__NR_getxattr] = {.slow = false, .name = "getxattr", .parser = {NULL}},
[__NR_lgetxattr] = {.slow = false, .name = "lgetxattr", .parser = {NULL}},
[__NR_fgetxattr] = {.slow = false, .name = "fgetxattr", .parser = {NULL}},
[__NR_listxattr] = {.slow = false, .name = "listxattr", .parser = {NULL}},
[__NR_llistxattr] = {.slow = false, .name = "llistxattr", .parser = {NULL}},
[__NR_flistxattr] = {.slow = false, .name = "flistxattr", .parser = {NULL}},
[__NR_getxattr] = {.slow = false, .name = "getxattr", .parser = {parse_long_arg,
parse_string_arg, parse_string_arg, parse_pointer_arg, parse_long_arg}},
[__NR_lgetxattr] = {.slow = false, .name = "lgetxattr", .parser = {parse_long_arg,
parse_string_arg, parse_string_arg, parse_pointer_arg, parse_long_arg}},
[__NR_fgetxattr] = {.slow = false, .name = "fgetxattr", .parser = {parse_long_arg,
parse_integer_arg, parse_string_arg, parse_pointer_arg, parse_long_arg}},
[__NR_listxattr] = {.slow = false, .name = "listxattr", .parser = {parse_long_arg,
parse_string_arg, parse_pointer_arg, parse_long_arg}},
[__NR_llistxattr] = {.slow = false, .name = "llistxattr", .parser = {parse_long_arg,
parse_string_arg, parse_pointer_arg, parse_long_arg}},
[__NR_flistxattr] = {.slow = false, .name = "flistxattr", .parser = {parse_long_arg,
parse_integer_arg, parse_pointer_arg, parse_long_arg}},
[__NR_removexattr] = {.slow = false, .name = "removexattr", .parser = {NULL}},
[__NR_lremovexattr] = {.slow = false, .name = "lremovexattr", .parser = {NULL}},
[__NR_fremovexattr] = {.slow = false, .name = "fremovexattr", .parser = {NULL}},
Expand Down
96 changes: 96 additions & 0 deletions libos/src/sys/libos_stat.c
Original file line number Diff line number Diff line change
Expand Up @@ -292,3 +292,99 @@ long libos_syscall_newfstatat(int dirfd, const char* pathname, struct stat* stat
put_dentry(dir);
return ret;
}

static int check_path(const char* path, int lookup_flags) {
int ret;
struct libos_dentry* dent = NULL;
lock(&g_dcache_lock);
ret = path_lookupat(/*start=*/NULL, path, lookup_flags, &dent);
unlock(&g_dcache_lock);
if (ret < 0)
return ret;
put_dentry(dent);
return 0;
}

long libos_syscall_getxattr(const char* path, const char* name, void* value,
size_t value_size) {
if (!is_user_string_readable(path) || !is_user_string_readable(name)
|| !is_user_memory_writable(value, value_size))
return -EFAULT;

int ret = check_path(path, LOOKUP_FOLLOW);
if (ret < 0)
return ret;

/* Gramine doesn't support mounting/setting xattrs, so the correct answer here is
* always "attribute not found". */
return -ENODATA;
}

long libos_syscall_lgetxattr(const char* path, const char* name, void* value,
size_t value_size) {
if (!is_user_string_readable(path) || !is_user_string_readable(name)
|| !is_user_memory_writable(value, value_size))
return -EFAULT;

int ret = check_path(path, LOOKUP_NO_FOLLOW);
if (ret < 0)
return ret;

/* Gramine doesn't support mounting/setting xattrs, so the correct answer here is
* always "attribute not found". */
return -ENODATA;
}

long libos_syscall_fgetxattr(int fd, const char* name, void* value, size_t value_size) {
if (!is_user_string_readable(name) || !is_user_memory_writable(value, value_size))
return -EFAULT;

struct libos_handle* hdl = get_fd_handle(fd, NULL, NULL);
if (!hdl)
return -EBADF;
put_handle(hdl);

/* Gramine doesn't support mounting/setting xattrs, so the correct answer here is
* always "attribute not found". */
return -ENODATA;
}

long libos_syscall_listxattr(const char* path, char* list, size_t list_size) {
if (!is_user_string_readable(path) || !is_user_memory_writable(list, list_size))
return -EFAULT;

int ret = check_path(path, LOOKUP_FOLLOW);
if (ret < 0)
return ret;

/* Gramine doesn't support mounting/setting xattrs, so the correct answer here is
* always an empty list of attributes. */
return 0;
}

long libos_syscall_llistxattr(const char* path, char* list, size_t list_size) {
if (!is_user_string_readable(path) || !is_user_memory_writable(list, list_size))
return -EFAULT;

int ret = check_path(path, LOOKUP_NO_FOLLOW);
if (ret < 0)
return ret;

/* Gramine doesn't support mounting/setting xattrs, so the correct answer here is
* always an empty list of attributes. */
return 0;
}

long libos_syscall_flistxattr(int fd, char* list, size_t list_size) {
if (!is_user_memory_writable(list, list_size))
return -EFAULT;

struct libos_handle* hdl = get_fd_handle(fd, NULL, NULL);
if (!hdl)
return -EBADF;
put_handle(hdl);

/* Gramine doesn't support mounting/setting xattrs, so the correct answer here is
* always an empty list of attributes. */
return 0;
}
12 changes: 6 additions & 6 deletions libos/test/ltp/ltp.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -535,11 +535,11 @@ must-pass =
[fdatasync03]
skip = yes

# no fgetxattr(), tries to use mounts and utimensat
# tries to use mounts and utimensat
[fgetxattr*]
skip = yes

# no flistxattr()
# requires fsetxattr
[flistxattr*]
skip = yes

Expand Down Expand Up @@ -751,7 +751,7 @@ skip = yes
[getuid*_16]
skip = yes

# no getxattr()
# requires setxattr
[getxattr*]
skip = yes

Expand Down Expand Up @@ -887,7 +887,7 @@ skip = yes
[leapsec01]
skip = yes

# no lgetxattr()
# requires lsetxattr
[lgetxattr*]
skip = yes

Expand Down Expand Up @@ -924,11 +924,11 @@ must-pass =
1
2

# no listxattr()
# requires setxattr
[listxattr*]
skip = yes

# no llistxattr()
# requires lsetxattr and symlink
[llistxattr*]
skip = yes

Expand Down

0 comments on commit 67a00de

Please sign in to comment.