ANDROID: fuse-bpf: Fix the issue of abnormal lseek system calls

fuse_lseek_backing was returning the offset as an int, which would then
be treated as an ERR if in the range 4G-4096 and 4G.

Although the call would appear to work correctly, the file position
would be incorrect according to a subsequent fseek with SEEK_CUR.

Based on a change by chenyuwen <chenyuwen1@meizu.com> who found and
fixed this issue.

Bug: 319219307
Change-Id: I3aef5fb22751a72ce2bd7674ee081956a89fc752
Signed-off-by: chenyuwen <chenyuwen1@meizu.com>
Signed-off-by: Paul Lawrence <paullawrence@google.com>
This commit is contained in:
Paul Lawrence 2024-01-09 10:02:00 -08:00
parent 947708f1ff
commit 204160394a
3 changed files with 220 additions and 8 deletions

View File

@ -401,23 +401,26 @@ int fuse_lseek_backing(struct fuse_bpf_args *fa, struct file *file, loff_t offse
struct file *backing_file = fuse_file->backing_file;
loff_t ret;
/* TODO: Handle changing of the file handle */
if (offset == 0) {
if (whence == SEEK_CUR) {
flo->offset = file->f_pos;
return flo->offset;
return 0;
}
if (whence == SEEK_SET) {
flo->offset = vfs_setpos(file, 0, 0);
return flo->offset;
return 0;
}
}
inode_lock(file->f_inode);
backing_file->f_pos = file->f_pos;
ret = vfs_llseek(backing_file, fli->offset, fli->whence);
flo->offset = ret;
if (!IS_ERR(ERR_PTR(ret))) {
flo->offset = ret;
ret = 0;
}
inode_unlock(file->f_inode);
return ret;
}

View File

@ -255,7 +255,7 @@ static int bpf_test_partial(const char *mount_dir)
TEST(src_fd = open(ft_src, O_DIRECTORY | O_RDONLY | O_CLOEXEC),
src_fd != -1);
TESTEQUAL(create_file(src_fd, s(test_name), 1, 2), 0);
TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_partial",
&bpf_fd, NULL, NULL), 0);
TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
@ -363,7 +363,7 @@ static int bpf_test_readdir(const char *mount_dir)
src_fd != -1);
TESTEQUAL(create_file(src_fd, s(names[0]), 1, 2), 0);
TESTEQUAL(create_file(src_fd, s(names[1]), 1, 2), 0);
TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_partial",
&bpf_fd, NULL, NULL), 0);
TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
@ -1490,6 +1490,8 @@ static int bpf_test_statfs(const char *mount_dir)
static int bpf_test_lseek(const char *mount_dir)
{
const char *file = "real";
const char *sparse_file = "sparse";
const off_t sparse_length = 0x100000000u;
const char *test_data = "data";
int result = TEST_FAILURE;
int src_fd = -1;
@ -1504,6 +1506,12 @@ static int bpf_test_lseek(const char *mount_dir)
TESTEQUAL(write(fd, test_data, strlen(test_data)), strlen(test_data));
TESTSYSCALL(close(fd));
fd = -1;
TEST(fd = openat(src_fd, sparse_file, O_CREAT | O_RDWR | O_CLOEXEC,
0777),
fd != -1);
TESTSYSCALL(ftruncate(fd, sparse_length));
TESTSYSCALL(close(fd));
fd = -1;
TESTEQUAL(install_elf_bpf("test_bpf.bpf", "test_trace",
&bpf_fd, NULL, NULL), 0);
TESTEQUAL(mount_fuse(mount_dir, bpf_fd, src_fd, &fuse_dev), 0);
@ -1518,6 +1526,18 @@ static int bpf_test_lseek(const char *mount_dir)
TESTEQUAL(bpf_test_trace("lseek"), 0);
TESTEQUAL(lseek(fd, 1, SEEK_DATA), 1);
TESTEQUAL(bpf_test_trace("lseek"), 0);
TESTSYSCALL(close(fd));
fd = -1;
TEST(fd = s_open(s_path(s(mount_dir), s(sparse_file)),
O_RDONLY | O_CLOEXEC),
fd != -1);
TESTEQUAL(lseek(fd, -256, SEEK_END), sparse_length - 256);
TESTEQUAL(lseek(fd, 0, SEEK_CUR), sparse_length - 256);
TESTSYSCALL(close(fd));
fd = -1;
result = TEST_SUCCESS;
out:
close(fd);

View File

@ -28,9 +28,9 @@ int readdir_test(struct fuse_bpf_args *fa)
}
}
SEC("test_trace")
SEC("test_partial")
/* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */
int trace_test(struct fuse_bpf_args *fa)
int partial_test(struct fuse_bpf_args *fa)
{
switch (fa->opcode) {
case FUSE_LOOKUP | FUSE_PREFILTER: {
@ -329,6 +329,195 @@ int trace_test(struct fuse_bpf_args *fa)
}
}
SEC("test_trace")
/* return FUSE_BPF_BACKING to use backing fs, 0 to pass to usermode */
int trace_test(struct fuse_bpf_args *fa)
{
switch (fa->opcode) {
case FUSE_LOOKUP | FUSE_PREFILTER: {
/* real and partial use backing file */
const char *name = fa->in_args[0].value;
bpf_printk("lookup %s", name);
return FUSE_BPF_BACKING;
}
case FUSE_ACCESS | FUSE_PREFILTER: {
bpf_printk("Access: %d", fa->nodeid);
return FUSE_BPF_BACKING;
}
case FUSE_CREATE | FUSE_PREFILTER:
bpf_printk("Create: %d", fa->nodeid);
return FUSE_BPF_BACKING;
case FUSE_MKNOD | FUSE_PREFILTER: {
const struct fuse_mknod_in *fmi = fa->in_args[0].value;
const char *name = fa->in_args[1].value;
bpf_printk("mknod %s %x %x", name, fmi->rdev | fmi->mode, fmi->umask);
return FUSE_BPF_BACKING;
}
case FUSE_MKDIR | FUSE_PREFILTER: {
const struct fuse_mkdir_in *fmi = fa->in_args[0].value;
const char *name = fa->in_args[1].value;
bpf_printk("mkdir %s %x %x", name, fmi->mode, fmi->umask);
return FUSE_BPF_BACKING;
}
case FUSE_RMDIR | FUSE_PREFILTER: {
const char *name = fa->in_args[0].value;
bpf_printk("rmdir %s", name);
return FUSE_BPF_BACKING;
}
case FUSE_RENAME | FUSE_PREFILTER: {
const char *oldname = fa->in_args[1].value;
const char *newname = fa->in_args[2].value;
bpf_printk("rename from %s", oldname);
bpf_printk("rename to %s", newname);
return FUSE_BPF_BACKING;
}
case FUSE_RENAME2 | FUSE_PREFILTER: {
const struct fuse_rename2_in *fri = fa->in_args[0].value;
uint32_t flags = fri->flags;
const char *oldname = fa->in_args[1].value;
const char *newname = fa->in_args[2].value;
bpf_printk("rename(%x) from %s", flags, oldname);
bpf_printk("rename to %s", newname);
return FUSE_BPF_BACKING;
}
case FUSE_UNLINK | FUSE_PREFILTER: {
const char *name = fa->in_args[0].value;
bpf_printk("unlink %s", name);
return FUSE_BPF_BACKING;
}
case FUSE_LINK | FUSE_PREFILTER: {
const struct fuse_link_in *fli = fa->in_args[0].value;
const char *link_name = fa->in_args[1].value;
bpf_printk("link %d %s", fli->oldnodeid, link_name);
return FUSE_BPF_BACKING;
}
case FUSE_SYMLINK | FUSE_PREFILTER: {
const char *link_name = fa->in_args[0].value;
const char *link_dest = fa->in_args[1].value;
bpf_printk("symlink from %s", link_name);
bpf_printk("symlink to %s", link_dest);
return FUSE_BPF_BACKING;
}
case FUSE_READLINK | FUSE_PREFILTER: {
const char *link_name = fa->in_args[0].value;
bpf_printk("readlink from", link_name);
return FUSE_BPF_BACKING;
}
case FUSE_OPEN | FUSE_PREFILTER: {
bpf_printk("open");
return FUSE_BPF_BACKING;
}
case FUSE_OPEN | FUSE_POSTFILTER:
bpf_printk("open postfilter");
return FUSE_BPF_USER_FILTER;
case FUSE_READ | FUSE_PREFILTER: {
const struct fuse_read_in *fri = fa->in_args[0].value;
bpf_printk("read %llu", fri->offset);
return FUSE_BPF_BACKING;
}
case FUSE_GETATTR | FUSE_PREFILTER: {
bpf_printk("getattr");
return FUSE_BPF_BACKING;
}
case FUSE_SETATTR | FUSE_PREFILTER: {
bpf_printk("setattr");
return FUSE_BPF_BACKING;
}
case FUSE_OPENDIR | FUSE_PREFILTER: {
bpf_printk("opendir");
return FUSE_BPF_BACKING;
}
case FUSE_READDIR | FUSE_PREFILTER: {
bpf_printk("readdir");
return FUSE_BPF_BACKING;
}
case FUSE_FLUSH | FUSE_PREFILTER: {
bpf_printk("Flush");
return FUSE_BPF_BACKING;
}
case FUSE_GETXATTR | FUSE_PREFILTER: {
const char *name = fa->in_args[1].value;
bpf_printk("getxattr %s", name);
return FUSE_BPF_BACKING;
}
case FUSE_LISTXATTR | FUSE_PREFILTER: {
const char *name = fa->in_args[1].value;
bpf_printk("listxattr %s", name);
return FUSE_BPF_BACKING;
}
case FUSE_SETXATTR | FUSE_PREFILTER: {
const char *name = fa->in_args[1].value;
unsigned int size = fa->in_args[2].size;
bpf_printk("setxattr %s %u", name, size);
return FUSE_BPF_BACKING;
}
case FUSE_REMOVEXATTR | FUSE_PREFILTER: {
const char *name = fa->in_args[0].value;
bpf_printk("removexattr %s", name);
return FUSE_BPF_BACKING;
}
case FUSE_CANONICAL_PATH | FUSE_PREFILTER: {
bpf_printk("canonical_path");
return FUSE_BPF_BACKING;
}
case FUSE_STATFS | FUSE_PREFILTER: {
bpf_printk("statfs");
return FUSE_BPF_BACKING;
}
case FUSE_LSEEK | FUSE_PREFILTER: {
const struct fuse_lseek_in *fli = fa->in_args[0].value;
bpf_printk("lseek type:%d, offset:%lld", fli->whence, fli->offset);
return FUSE_BPF_BACKING;
}
default:
bpf_printk("Unknown opcode %d", fa->opcode);
return FUSE_BPF_BACKING;
}
}
SEC("test_hidden")
int trace_hidden(struct fuse_bpf_args *fa)
{