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:
parent
947708f1ff
commit
204160394a
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user