Skip to content

Commit cc14ae1

Browse files
authored
Merge pull request #351 from abhinavagarwal07/fix-conntab-null-deref
fix conntab lookup after rename in sshfs_release
2 parents 78f807b + 033a1d4 commit cc14ae1

2 files changed

Lines changed: 42 additions & 14 deletions

File tree

sshfs.c

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,11 @@ struct read_chunk {
280280
struct sshfs_io sio;
281281
};
282282

283+
struct conntab_entry {
284+
unsigned refcount;
285+
struct conn *conn;
286+
};
287+
283288
struct sshfs_file {
284289
struct buffer handle;
285290
struct list_head write_reqs;
@@ -289,15 +294,11 @@ struct sshfs_file {
289294
off_t next_pos;
290295
int is_seq;
291296
struct conn *conn;
297+
struct conntab_entry *ce;
292298
int connver;
293299
int modifver;
294300
};
295301

296-
struct conntab_entry {
297-
unsigned refcount;
298-
struct conn *conn;
299-
};
300-
301302
struct sshfs {
302303
char *directport;
303304
char *ssh_command;
@@ -2768,6 +2769,12 @@ static int sshfs_utimens(const char *path, const struct timespec tv[2],
27682769
return err;
27692770
}
27702771

2772+
static gboolean conntab_entry_is(gpointer key, gpointer value, gpointer data)
2773+
{
2774+
(void) key;
2775+
return value == data;
2776+
}
2777+
27712778
static int sshfs_open_common(const char *path, mode_t mode,
27722779
struct fuse_file_info *fi)
27732780
{
@@ -2828,12 +2835,13 @@ static int sshfs_open_common(const char *path, mode_t mode,
28282835
g_hash_table_insert(sshfs.conntab, g_strdup(path), ce);
28292836
}
28302837
sf->conn = ce->conn;
2838+
sf->ce = ce;
28312839
ce->refcount++;
28322840
sf->conn->file_count++;
28332841
assert(sf->conn->file_count > 0);
28342842
} else {
28352843
sf->conn = &sshfs.conns[0];
2836-
ce = NULL; // only to silence compiler warning
2844+
sf->ce = NULL;
28372845
}
28382846
sf->connver = sf->conn->connver;
28392847
pthread_mutex_unlock(&sshfs.lock);
@@ -2873,10 +2881,12 @@ static int sshfs_open_common(const char *path, mode_t mode,
28732881
if (sshfs.max_conns > 1) {
28742882
pthread_mutex_lock(&sshfs.lock);
28752883
sf->conn->file_count--;
2876-
ce->refcount--;
2877-
if(ce->refcount == 0) {
2878-
g_hash_table_remove(sshfs.conntab, path);
2879-
g_free(ce);
2884+
sf->ce->refcount--;
2885+
if (sf->ce->refcount == 0) {
2886+
g_hash_table_foreach_remove(sshfs.conntab,
2887+
conntab_entry_is,
2888+
sf->ce);
2889+
g_free(sf->ce);
28802890
}
28812891
pthread_mutex_unlock(&sshfs.lock);
28822892
}
@@ -2947,20 +2957,20 @@ static int sshfs_release(const char *path, struct fuse_file_info *fi)
29472957
{
29482958
struct sshfs_file *sf = get_sshfs_file(fi);
29492959
struct buffer *handle = &sf->handle;
2950-
struct conntab_entry *ce;
29512960
if (sshfs_file_is_conn(sf)) {
29522961
sshfs_flush(path, fi);
29532962
sftp_request(sf->conn, SSH_FXP_CLOSE, handle, 0, NULL);
29542963
}
29552964
buf_free(handle);
29562965
chunk_put_locked(sf->readahead);
29572966
if (sshfs.max_conns > 1) {
2967+
struct conntab_entry *ce = sf->ce;
29582968
pthread_mutex_lock(&sshfs.lock);
29592969
sf->conn->file_count--;
2960-
ce = g_hash_table_lookup(sshfs.conntab, path);
29612970
ce->refcount--;
2962-
if(ce->refcount == 0) {
2963-
g_hash_table_remove(sshfs.conntab, path);
2971+
if (ce->refcount == 0) {
2972+
g_hash_table_foreach_remove(sshfs.conntab,
2973+
conntab_entry_is, ce);
29642974
g_free(ce);
29652975
}
29662976
pthread_mutex_unlock(&sshfs.lock);

test/test_sshfs.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ def test_sshfs(
168168
tst_mkdir_exist(mnt_dir)
169169
tst_readdir_repeated(mnt_dir)
170170
tst_rename_sibling(mnt_dir)
171+
tst_rename_open_release(mnt_dir)
171172
except Exception as exc:
172173
cleanup(mount_process, mnt_dir)
173174
raise exc
@@ -503,6 +504,23 @@ def tst_rename_sibling(mnt_dir):
503504
os.unlink(name_c)
504505

505506

507+
def tst_rename_open_release(mnt_dir):
508+
src = pjoin(mnt_dir, name_generator())
509+
dst = pjoin(mnt_dir, name_generator())
510+
511+
fd = os.open(src, os.O_CREAT | os.O_RDWR)
512+
try:
513+
os.write(fd, b"data")
514+
os.rename(src, dst)
515+
finally:
516+
os.close(fd)
517+
518+
assert not os.path.exists(src)
519+
with open(dst, "rb") as fh:
520+
assert fh.read() == b"data"
521+
os.unlink(dst)
522+
523+
506524
def tst_link(mnt_dir, cache_timeout):
507525
name1 = pjoin(mnt_dir, name_generator())
508526
name2 = pjoin(mnt_dir, name_generator())

0 commit comments

Comments
 (0)