summaryrefslogtreecommitdiffstats
path: root/xlators/mount/fuse/src
diff options
context:
space:
mode:
authorKaleb S KEITHLEY <kkeithle@redhat.com>2016-01-21 17:03:17 -0500
committerRaghavendra G <rgowdapp@redhat.com>2016-02-02 21:16:04 -0800
commit4ae9ac6dd48d378984fa3a34a6b63d90bc74e431 (patch)
tree32316f582bee60a1d5e89e781ae5e9ab6168d766 /xlators/mount/fuse/src
parent10153901f0649b2d12c505a0f9fbef7a69acf128 (diff)
fuse: use-after-free fix in fuse-bridge, revisited
Prompted by the email exchange in gluster-devel between Oleksandr Natalenko, xavi, and soumyak, I looked at this because the fuse client on the longevity cluster has also been suffering from a serious memory leak for some time. (longevity cluster is currently running 3.7.6) The longevity cluster manifests the same kernel notifier loop terminated log message the Oleksandr sees, and some sample runs suggest that the length passed to the (sys_)write call is unexpectedly and abnormally large. Basically this fix a) uses correct types for len and rv, b) copies the len from potentially incorrectly aligned memory (in a way that should minimize potential performance issues related to accessing unaligned memory.) c) changes log level of the kernel notifier loop terminated message d) fixes a potential mutex lock/unlock issue See Change-Id: Icedb3525706f59803878bb37ef6b4ffe4a986880 BUG: 1288857 http://review.gluster.org/13274 Change-Id: I1a2f957a95978468baa33c2b1f3667934d88939c BUG: 1288922 Signed-off-by: Kaleb S KEITHLEY <kkeithle@redhat.com> Reviewed-on: http://review.gluster.org/13275 Smoke: Gluster Build System <jenkins@build.gluster.com> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org> CentOS-regression: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Raghavendra G <rgowdapp@redhat.com>
Diffstat (limited to 'xlators/mount/fuse/src')
-rw-r--r--xlators/mount/fuse/src/fuse-bridge.c50
1 files changed, 37 insertions, 13 deletions
diff --git a/xlators/mount/fuse/src/fuse-bridge.c b/xlators/mount/fuse/src/fuse-bridge.c
index 72dd60c4ed4..bd7d5adf9db 100644
--- a/xlators/mount/fuse/src/fuse-bridge.c
+++ b/xlators/mount/fuse/src/fuse-bridge.c
@@ -3836,12 +3836,13 @@ fuse_setlk (xlator_t *this, fuse_in_header_t *finh, void *msg)
static void *
notify_kernel_loop (void *data)
{
+ uint32_t len = 0;
+ ssize_t rv = 0;
xlator_t *this = NULL;
fuse_private_t *priv = NULL;
- struct fuse_out_header *fouh = NULL;
- ssize_t rv = 0;
- ssize_t len = 0;
fuse_invalidate_node_t *node = NULL;
+ fuse_invalidate_node_t *tmp = NULL;
+ struct fuse_out_header *pfoh = NULL;
this = data;
priv = this->private;
@@ -3856,28 +3857,51 @@ notify_kernel_loop (void *data)
node = list_entry (priv->invalidate_list.next,
fuse_invalidate_node_t, next);
- if (node == NULL)
- continue;
-
list_del_init (&node->next);
}
pthread_mutex_unlock (&priv->invalidate_mutex);
+ pfoh = (struct fuse_out_header *)node->inval_buf;
+ memcpy (&len, &pfoh->len, sizeof(len));
+ /*
+ * a simple
+ * len = pfoh->len;
+ * works on x86, but takes a multiple insn cycle hit
+ * when pfoh->len is not correctly aligned, possibly
+ * even stalling the insn pipeline.
+ * Other architectures will not be so forgiving. If
+ * we're lucky the memcpy will be inlined by the
+ * compiler, and might be as fast or faster without
+ * the risk of stalling the insn pipeline.
+ */
- fouh = (struct fuse_out_header *)node->inval_buf;
+ rv = write (priv->fd, node->inval_buf, len);
- len = fouh->len;
- rv = write (priv->fd, node->inval_buf, fouh->len);
+ GF_FREE (node);
- if (rv != len && !(rv == -1 && errno == ENOENT))
+ if (rv == -1 && errno == EBADF)
break;
- GF_FREE (node);
+
+ if (rv != len && !(rv == -1 && errno == ENOENT)) {
+ gf_log ("glusterfs-fuse", GF_LOG_INFO,
+ "len: %u, rv: %zd, errno: %d", len, rv, errno);
+ }
}
- gf_log ("glusterfs-fuse", GF_LOG_INFO,
+ gf_log ("glusterfs-fuse", GF_LOG_ERROR,
"kernel notifier loop terminated");
- GF_FREE (node);
+ pthread_mutex_lock (&priv->invalidate_mutex);
+ {
+ priv->reverse_fuse_thread_started = _gf_false;
+ list_for_each_entry_safe (node, tmp, &priv->invalidate_list,
+ next) {
+ list_del_init (&node->next);
+ GF_FREE (node);
+ }
+ }
+ pthread_mutex_unlock (&priv->invalidate_mutex);
+
return NULL;
}
#endif