From f52f71df3373185c4d18414aad57c4e8995a4393 Mon Sep 17 00:00:00 2001 From: Bernd Schubert Date: Sat, 22 Mar 2025 23:57:55 +0100 Subject: fuse: Fix want flag conversion 32-bit conn->want flags been left to be ABI compatible to 3.10, even though the so version was changed. The more recent way is to use fuse_set_feature_flag(), which will use conn->want_ext. Given that we now have two flags (want and want_ext), we need to convert and that brought several issues - If the application sets conn->want, that needs to be set into the lower 32 bit of conn->want_ext. As the application might actually unset values, it really has to be a copy and not just 'or' - fixed now. - convert_to_conn_want_ext() actually needs to check for _modified_ conn->want and conn->want_ext - convert_to_conn_want_ext() must consider being called from high and lowlevel interfact, with different want_ext_default and want_default values. It is only a failure, if the application changed both, conn->want and conn->want_ext. This function was failing in issue #1171, because high level fuse_fs_init() was changing values and then lowlevel do_init() was incorrectly failing on that. This also adds a new test (test_want_conversion) and sets values into example/{hello.c,hello_ll.c} Also some more internal users of conn->want are converted to fuse_{set,unset}_feature_flag(). Closes: https://github.com/libfuse/libfuse/issues/1171 Signed-off-by: Bernd Schubert (cherry picked from commit f68970cd235a7e14026ca0f6240428bbebe8223b) --- lib/fuse.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'lib/fuse.c') diff --git a/lib/fuse.c b/lib/fuse.c index 9335429..136f0c2 100644 --- a/lib/fuse.c +++ b/lib/fuse.c @@ -10,6 +10,8 @@ */ #define _GNU_SOURCE +#include "fuse.h" +#include #include "fuse_config.h" #include "fuse_i.h" @@ -17,7 +19,9 @@ #include "fuse_opt.h" #include "fuse_misc.h" #include "fuse_kernel.h" +#include "util.h" +#include #include #include #include @@ -2606,13 +2610,34 @@ void fuse_fs_init(struct fuse_fs *fs, struct fuse_conn_info *conn, { fuse_get_context()->private_data = fs->user_data; if (!fs->op.write_buf) - conn->want &= ~FUSE_CAP_SPLICE_READ; + fuse_unset_feature_flag(conn, FUSE_CAP_SPLICE_READ); if (!fs->op.lock) - conn->want &= ~FUSE_CAP_POSIX_LOCKS; + fuse_unset_feature_flag(conn, FUSE_CAP_POSIX_LOCKS); if (!fs->op.flock) - conn->want &= ~FUSE_CAP_FLOCK_LOCKS; - if (fs->op.init) + fuse_unset_feature_flag(conn, FUSE_CAP_FLOCK_LOCKS); + if (fs->op.init) { + uint64_t want_ext_default = conn->want_ext; + uint32_t want_default = fuse_lower_32_bits(conn->want_ext); + int rc; + + conn->want = want_default; fs->user_data = fs->op.init(conn, cfg); + + rc = convert_to_conn_want_ext(conn, want_ext_default, + want_default); + + if (rc != 0) { + /* + * This is a grave developer error, but + * we cannot return an error here, as the function + * signature does not allow it. + */ + fuse_log( + FUSE_LOG_ERR, + "fuse: Aborting due to invalid conn want flags.\n"); + _exit(EXIT_FAILURE); + } + } } static int fuse_init_intr_signal(int signum, int *installed); -- cgit v1.2.3