Chris Clayton via fuse-devel
2017-07-13 13:01:40 UTC
Under certain circumstances, lib/fuse.c:fuse_new_30() calls lib/fuse.c:fuse_new(). Once built,
libfuse.so.3.1.0 contains three (versioned) symbols with the name fuse_new:
- ***@FUSE_3.0, an alias of fuse_new_30();
- another ***@FUSE_3.0, the real fuse_new(); and
- ***@FUSE_3.1, another reference to the real fuse_new().
(These versioned symbols are intended to provide backward compatibility for applications written for/built.
against libfuse3.so.3.0.x).
Unfortunately, the loader uses the first instance of ***@FUSE_3.0 listed above to resolve the call to fuse_new()
from fuse_new_30(). Obviously, this causes infinite recursion and, in the case of sshfs-3.0.0, a segmentation fault.
Fix this by renaming fuse_new() to fuse_new_31() and calling it explicitly from fuse_new_30(). Also create a
versioned symbol ***@FUSE_3.1 as an alias of fuse_new_31(). This gives us a library containing only two
symbols with the name fuse_new:
- ***@FUSE_3.0, an alias of fuse_new_30(); and
- ***@FUSE_3.1, an alias of fuse_new_31().
***@FUSE_3.1 is specified to be the default symbol used to resolve unversioned references to fuse_new();
Signed-off-by: Chris Clayton <***@googlemail.com>
---
diff -rup fuse-3.1.0.orig/lib/fuse.c fuse-3.1.0/lib/fuse.c
--- fuse-3.1.0.orig/lib/fuse.c 2017-07-08 11:48:08.000000000 +0100
+++ fuse-3.1.0/lib/fuse.c 2017-07-13 06:21:30.295879232 +0100
@@ -196,6 +196,12 @@ struct fuse_context_i {
fuse_req_t req;
};
+
+/* private function that (via symbol versioning below) is the default fuse_new()
+ * implementation for programs that define FUSE_USE_VERSION not equal to 30 */
+struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op,
+ size_t op_size, void *private_data);
+
/* Defined by FUSE_REGISTER_MODULE() in lib/modules/subdir.c and iconv.c. */
extern fuse_module_factory_t fuse_module_subdir_factory;
extern fuse_module_factory_t fuse_module_iconv_factory;
@@ -4629,7 +4635,7 @@ void fuse_stop_cleanup_thread(struct fus
/* Emulates 3.0-style fuse_new(), which processes
--help */
FUSE_SYMVER(".symver fuse_new_30,***@FUSE_3.0");
-FUSE_SYMVER(".symver fuse_new,fuse_new@@FUSE_3.1");
+FUSE_SYMVER(".symver fuse_new_31,fuse_new@@FUSE_3.1");
struct fuse *fuse_new_30(struct fuse_args *args,
const struct fuse_operations *op,
size_t op_size, void *user_data)
@@ -4649,10 +4655,10 @@ struct fuse *fuse_new_30(struct fuse_arg
fuse_lib_help(args);
return NULL;
} else
- return fuse_new(args, op, op_size, user_data);
+ return fuse_new_31(args, op, op_size, user_data);
}
-struct fuse *fuse_new(struct fuse_args *args,
+struct fuse *fuse_new_31(struct fuse_args *args,
const struct fuse_operations *op,
size_t op_size, void *user_data)
{
libfuse.so.3.1.0 contains three (versioned) symbols with the name fuse_new:
- ***@FUSE_3.0, an alias of fuse_new_30();
- another ***@FUSE_3.0, the real fuse_new(); and
- ***@FUSE_3.1, another reference to the real fuse_new().
(These versioned symbols are intended to provide backward compatibility for applications written for/built.
against libfuse3.so.3.0.x).
Unfortunately, the loader uses the first instance of ***@FUSE_3.0 listed above to resolve the call to fuse_new()
from fuse_new_30(). Obviously, this causes infinite recursion and, in the case of sshfs-3.0.0, a segmentation fault.
Fix this by renaming fuse_new() to fuse_new_31() and calling it explicitly from fuse_new_30(). Also create a
versioned symbol ***@FUSE_3.1 as an alias of fuse_new_31(). This gives us a library containing only two
symbols with the name fuse_new:
- ***@FUSE_3.0, an alias of fuse_new_30(); and
- ***@FUSE_3.1, an alias of fuse_new_31().
***@FUSE_3.1 is specified to be the default symbol used to resolve unversioned references to fuse_new();
Signed-off-by: Chris Clayton <***@googlemail.com>
---
diff -rup fuse-3.1.0.orig/lib/fuse.c fuse-3.1.0/lib/fuse.c
--- fuse-3.1.0.orig/lib/fuse.c 2017-07-08 11:48:08.000000000 +0100
+++ fuse-3.1.0/lib/fuse.c 2017-07-13 06:21:30.295879232 +0100
@@ -196,6 +196,12 @@ struct fuse_context_i {
fuse_req_t req;
};
+
+/* private function that (via symbol versioning below) is the default fuse_new()
+ * implementation for programs that define FUSE_USE_VERSION not equal to 30 */
+struct fuse *fuse_new_31(struct fuse_args *args, const struct fuse_operations *op,
+ size_t op_size, void *private_data);
+
/* Defined by FUSE_REGISTER_MODULE() in lib/modules/subdir.c and iconv.c. */
extern fuse_module_factory_t fuse_module_subdir_factory;
extern fuse_module_factory_t fuse_module_iconv_factory;
@@ -4629,7 +4635,7 @@ void fuse_stop_cleanup_thread(struct fus
/* Emulates 3.0-style fuse_new(), which processes
--help */
FUSE_SYMVER(".symver fuse_new_30,***@FUSE_3.0");
-FUSE_SYMVER(".symver fuse_new,fuse_new@@FUSE_3.1");
+FUSE_SYMVER(".symver fuse_new_31,fuse_new@@FUSE_3.1");
struct fuse *fuse_new_30(struct fuse_args *args,
const struct fuse_operations *op,
size_t op_size, void *user_data)
@@ -4649,10 +4655,10 @@ struct fuse *fuse_new_30(struct fuse_arg
fuse_lib_help(args);
return NULL;
} else
- return fuse_new(args, op, op_size, user_data);
+ return fuse_new_31(args, op, op_size, user_data);
}
-struct fuse *fuse_new(struct fuse_args *args,
+struct fuse *fuse_new_31(struct fuse_args *args,
const struct fuse_operations *op,
size_t op_size, void *user_data)
{