Skip to content

Commit 32a2511

Browse files
committed
[LibOS] Protect handle->dentry with handle->lock
Signed-off-by: g2flyer <[email protected]>
1 parent 649a8f5 commit 32a2511

14 files changed

+109
-63
lines changed

libos/include/libos_handle.h

+1
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@ struct libos_handle {
165165
refcount_t ref_count;
166166

167167
struct libos_fs* fs;
168+
/* dentry can change due to rename, so to derefence or update requires holding `lock`. */
168169
struct libos_dentry* dentry;
169170

170171
/*

libos/src/bookkeep/libos_handle.c

+37-30
Original file line numberDiff line numberDiff line change
@@ -324,25 +324,28 @@ static struct libos_handle* __detach_fd_handle(struct libos_fd_handle* fd, int*
324324
}
325325

326326
static int clear_posix_locks(struct libos_handle* handle) {
327-
if (handle && handle->dentry) {
328-
/* Clear file (POSIX) locks for a file. We are required to do that every time a FD is
329-
* closed, even if the process holds other handles for that file, or duplicated FDs for the
330-
* same handle. */
331-
struct libos_file_lock file_lock = {
332-
.family = FILE_LOCK_POSIX,
333-
.type = F_UNLCK,
334-
.start = 0,
335-
.end = FS_LOCK_EOF,
336-
.pid = g_process.pid,
337-
};
338-
int ret = file_lock_set(handle->dentry, &file_lock, /*block=*/false);
339-
if (ret < 0) {
340-
log_warning("error releasing locks: %s", unix_strerror(ret));
341-
return ret;
327+
int ret = 0;
328+
if (handle) {
329+
lock(&handle->lock);
330+
if (handle->dentry) {
331+
/* Clear file (POSIX) locks for a file. We are required to do that every time a FD is
332+
* closed, even if the process holds other handles for that file, or duplicated FDs for
333+
* the same handle. */
334+
struct libos_file_lock file_lock = {
335+
.family = FILE_LOCK_POSIX,
336+
.type = F_UNLCK,
337+
.start = 0,
338+
.end = FS_LOCK_EOF,
339+
.pid = g_process.pid,
340+
};
341+
ret = file_lock_set(handle->dentry, &file_lock, /*block=*/false);
342+
if (ret < 0) {
343+
log_warning("error releasing locks: %s", unix_strerror(ret));
344+
}
342345
}
346+
unlock(&handle->lock);
343347
}
344-
345-
return 0;
348+
return ret;
346349
}
347350

348351
struct libos_handle* detach_fd_handle(uint32_t fd, int* flags,
@@ -512,20 +515,24 @@ static void destroy_handle(struct libos_handle* hdl) {
512515

513516
static int clear_flock_locks(struct libos_handle* hdl) {
514517
/* Clear flock (BSD) locks for a file. We are required to do that when the handle is closed. */
515-
if (hdl && hdl->dentry && hdl->created_by_process) {
516-
assert(hdl->ref_count == 0);
517-
struct libos_file_lock file_lock = {
518-
.family = FILE_LOCK_FLOCK,
519-
.type = F_UNLCK,
520-
.handle_id = hdl->id,
521-
};
522-
int ret = file_lock_set(hdl->dentry, &file_lock, /*block=*/false);
523-
if (ret < 0) {
524-
log_warning("error releasing locks: %s", unix_strerror(ret));
525-
return ret;
518+
int ret = 0;
519+
if (hdl) {
520+
lock(&hdl->lock);
521+
if (hdl->dentry && hdl->created_by_process) {
522+
assert(hdl->ref_count == 0);
523+
struct libos_file_lock file_lock = {
524+
.family = FILE_LOCK_FLOCK,
525+
.type = F_UNLCK,
526+
.handle_id = hdl->id,
527+
};
528+
int ret = file_lock_set(hdl->dentry, &file_lock, /*block=*/false);
529+
if (ret < 0) {
530+
log_warning("error releasing locks: %s", unix_strerror(ret));
531+
}
526532
}
533+
unlock(&hdl->lock);
527534
}
528-
return 0;
535+
return ret;
529536
}
530537

531538
void put_handle(struct libos_handle* hdl) {
@@ -549,7 +556,7 @@ void put_handle(struct libos_handle* hdl) {
549556
hdl->pal_handle = NULL;
550557
}
551558

552-
if (hdl->dentry) {
559+
if (hdl->dentry) { /* no locking needed as no other reference exists */
553560
(void)clear_flock_locks(hdl);
554561
put_dentry(hdl->dentry);
555562
}

libos/src/fs/libos_fs_pseudo.c

+3
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,9 @@ static int pseudo_stat(struct libos_dentry* dent, struct stat* buf) {
266266
}
267267

268268
static int pseudo_hstat(struct libos_handle* handle, struct stat* buf) {
269+
/* Note: derefence handle->dentry in general has to be protected by handle->lock as it could
270+
* change due to rename. However, as pseudo-fs does not support rename we can safely omit it
271+
* here (or push it on the numerous callers of fs_op->hstat). */
269272
return pseudo_istat(handle->dentry, handle->inode, buf);
270273
}
271274

libos/src/fs/libos_namei.c

+5-3
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,7 @@ static void assoc_handle_with_dentry(struct libos_handle* hdl, struct libos_dent
367367
assert(locked(&g_dcache_lock));
368368
assert(dent->inode);
369369

370-
hdl->dentry = dent;
370+
hdl->dentry = dent; /* not-yet-shared handle, so no look needed. */
371371
get_dentry(dent);
372372

373373
hdl->inode = dent->inode;
@@ -381,7 +381,7 @@ static void assoc_handle_with_dentry(struct libos_handle* hdl, struct libos_dent
381381
int dentry_open(struct libos_handle* hdl, struct libos_dentry* dent, int flags) {
382382
assert(locked(&g_dcache_lock));
383383
assert(dent->inode);
384-
assert(!hdl->dentry);
384+
assert(!hdl->dentry); /* not-yet-shared handle, so no look needed. */
385385

386386
int ret;
387387
struct libos_fs* fs = dent->inode->fs;
@@ -431,7 +431,7 @@ int open_namei(struct libos_handle* hdl, struct libos_dentry* start, const char*
431431
assert(hdl);
432432

433433
if (hdl)
434-
assert(!hdl->dentry);
434+
assert(!hdl->dentry); /* not-yet-shared handle, so no look needed. */
435435

436436
lock(&g_dcache_lock);
437437

@@ -741,8 +741,10 @@ int get_dirfd_dentry(int dirfd, struct libos_dentry** dir) {
741741
return -ENOTDIR;
742742
}
743743

744+
lock(&hdl->lock); /* while hdl->is_dir is immutable, hdl->dentry can change due to rename */
744745
get_dentry(hdl->dentry);
745746
*dir = hdl->dentry;
747+
unlock(&hdl->lock);
746748
put_handle(hdl);
747749
return 0;
748750
}

libos/src/fs/proc/thread.c

+8
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ int proc_thread_follow_link(struct libos_dentry* dent, char** out_target) {
2929
dent = g_process.cwd;
3030
get_dentry(dent);
3131
} else if (strcmp(name, "exe") == 0) {
32+
lock(&g_process.exec->lock);
3233
dent = g_process.exec->dentry;
3334
if (dent)
3435
get_dentry(dent);
36+
unlock(&g_process.exec->lock);
3537
}
3638

3739
unlock(&g_process.fs_lock);
@@ -91,11 +93,13 @@ int proc_thread_maps_load(struct libos_dentry* dent, char** out_data, size_t* ou
9193
retry_emit_vma:
9294
if (vma->file) {
9395
int dev_major = 0, dev_minor = 0;
96+
lock(&vma->file->lock);
9497
unsigned long ino = vma->file->dentry ? dentry_ino(vma->file->dentry) : 0;
9598
char* path = NULL;
9699

97100
if (vma->file->dentry)
98101
dentry_abs_path(vma->file->dentry, &path, /*size=*/NULL);
102+
unlock(&vma->file->lock);
99103

100104
EMIT(ADDR_FMT(start), start);
101105
EMIT("-");
@@ -310,6 +314,7 @@ int proc_thread_fd_follow_link(struct libos_dentry* dent, char** out_target) {
310314
int ret;
311315
struct libos_handle* hdl = handle_map->map[fd]->handle;
312316

317+
lock(&hdl->lock);
313318
if (hdl->dentry) {
314319
ret = dentry_abs_path(hdl->dentry, out_target, /*size=*/NULL);
315320
} else {
@@ -318,6 +323,7 @@ int proc_thread_fd_follow_link(struct libos_dentry* dent, char** out_target) {
318323
*out_target = describe_handle(hdl);
319324
ret = *out_target ? 0 : -ENOMEM;
320325
}
326+
unlock(&hdl->lock);
321327

322328
rwlock_read_unlock(&handle_map->lock);
323329

@@ -457,9 +463,11 @@ int proc_thread_stat_load(struct libos_dentry* dent, char** out_data, size_t* ou
457463

458464
char comm[16] = {0};
459465
lock(&g_process.fs_lock);
466+
lock(&g_process.exec->lock);
460467
size_t name_length = g_process.exec->dentry->name_len;
461468
memcpy(comm, g_process.exec->dentry->name,
462469
name_length > sizeof(comm) - 1 ? sizeof(comm) - 1 : name_length);
470+
unlock(&g_process.exec->lock);
463471
unlock(&g_process.fs_lock);
464472
size_t virtual_mem_size = get_total_memory_usage();
465473

libos/src/ipc/libos_ipc_process_info.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,11 @@ int ipc_pid_getmeta_callback(IDTYPE src, void* msg_data, uint64_t seq) {
101101
struct libos_dentry* dent = NULL;
102102
switch (msgin->code) {
103103
case PID_META_EXEC:
104-
if (g_process.exec)
104+
if (g_process.exec) {
105+
lock(&g_process.exec->lock);
105106
dent = g_process.exec->dentry;
107+
unlock(&g_process.exec->lock);
108+
}
106109
break;
107110
case PID_META_CWD:
108111
dent = g_process.cwd;

libos/src/libos_rtld.c

+2
Original file line numberDiff line numberDiff line change
@@ -597,10 +597,12 @@ static int load_and_check_shebang(struct libos_handle* file, const char* pathnam
597597
ret = read_partial_fragment(file, shebang, sizeof(shebang), /*offset=*/0, &shebang_len);
598598
if (ret < 0 || shebang_len < 2 || shebang[0] != '#' || shebang[1] != '!') {
599599
char* path = NULL;
600+
lock(&file->lock);
600601
if (file->dentry) {
601602
/* this may fail, but we are already inside a more serious error handler */
602603
dentry_abs_path(file->dentry, &path, /*size=*/NULL);
603604
}
605+
unlock(&file->lock);
604606
log_debug("Failed to read shebang line from %s", path ? path : "(unknown)");
605607
free(path);
606608
return -ENOEXEC;

libos/src/sys/libos_fcntl.c

+24-11
Original file line numberDiff line numberDiff line change
@@ -199,29 +199,34 @@ long libos_syscall_fcntl(int fd, int cmd, unsigned long arg) {
199199
break;
200200
}
201201

202-
if (!hdl->dentry) {
202+
lock(&hdl->lock);
203+
struct libos_dentry* dent = hdl->dentry;
204+
205+
if (!dent) {
203206
/* TODO: Linux allows locks on pipes etc. Our locks work only for "normal" files
204207
* that have a dentry. */
205208
ret = -EINVAL;
206-
break;
209+
goto out_setlkw_unlock;
207210
}
208211

209212
if (fl->l_type == F_RDLCK && !(hdl->acc_mode & MAY_READ)) {
210213
ret = -EINVAL;
211-
break;
214+
goto out_setlkw_unlock;
212215
}
213216

214217
if (fl->l_type == F_WRLCK && !(hdl->acc_mode & MAY_WRITE)) {
215218
ret = -EINVAL;
216-
break;
219+
goto out_setlkw_unlock;
217220
}
218221

219222
struct libos_file_lock file_lock;
220223
ret = flock_to_file_lock(fl, hdl, &file_lock);
221224
if (ret < 0)
222-
break;
225+
goto out_setlkw_unlock;
223226

224-
ret = file_lock_set(hdl->dentry, &file_lock, /*wait=*/cmd == F_SETLKW);
227+
ret = file_lock_set(dent, &file_lock, /*wait=*/cmd == F_SETLKW);
228+
out_setlkw_unlock:
229+
unlock(&hdl->lock);
225230
break;
226231
}
227232

@@ -234,9 +239,12 @@ long libos_syscall_fcntl(int fd, int cmd, unsigned long arg) {
234239
break;
235240
}
236241

237-
if (!hdl->dentry) {
242+
lock(&hdl->lock);
243+
struct libos_dentry* dent = hdl->dentry;
244+
245+
if (!dent) {
238246
ret = -EINVAL;
239-
break;
247+
goto out_getlkw_unlock;
240248
}
241249

242250
struct libos_file_lock file_lock;
@@ -246,13 +254,13 @@ long libos_syscall_fcntl(int fd, int cmd, unsigned long arg) {
246254

247255
if (file_lock.type == F_UNLCK) {
248256
ret = -EINVAL;
249-
break;
257+
goto out_getlkw_unlock;
250258
}
251259

252260
struct libos_file_lock file_lock2;
253-
ret = file_lock_get(hdl->dentry, &file_lock, &file_lock2);
261+
ret = file_lock_get(dent, &file_lock, &file_lock2);
254262
if (ret < 0)
255-
break;
263+
goto out_getlkw_unlock;
256264

257265
fl->l_type = file_lock2.type;
258266
if (file_lock2.type != F_UNLCK) {
@@ -267,6 +275,8 @@ long libos_syscall_fcntl(int fd, int cmd, unsigned long arg) {
267275
fl->l_pid = file_lock2.pid;
268276
}
269277
ret = 0;
278+
out_getlkw_unlock:
279+
unlock(&hdl->lock);
270280
break;
271281
}
272282

@@ -342,7 +352,10 @@ long libos_syscall_flock(unsigned int fd, unsigned int cmd) {
342352
.type = lock_type,
343353
.handle_id = hdl->id,
344354
};
355+
356+
lock(&hdl->lock);
345357
ret = file_lock_set(hdl->dentry, &file_lock, !(cmd & LOCK_NB));
358+
unlock(&hdl->lock);
346359
out:
347360
put_handle(hdl);
348361
return ret;

libos/src/sys/libos_getcwd.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ long libos_syscall_fchdir(int fd) {
8383
return -EBADF;
8484

8585
int ret;
86-
lock(&g_dcache_lock);
86+
lock(&g_dcache_lock); /* for dent->inode */
87+
lock(&g_process.fs_lock); /* for g_process.cwd */
88+
lock(&hdl->lock); /* for hdl->dentry */
8789

8890
struct libos_dentry* dent = hdl->dentry;
8991

@@ -101,14 +103,15 @@ long libos_syscall_fchdir(int fd) {
101103
goto out;
102104
}
103105

104-
lock(&g_process.fs_lock);
105106
get_dentry(dent);
106107
put_dentry(g_process.cwd);
107108
g_process.cwd = dent;
108-
unlock(&g_process.fs_lock);
109109
ret = 0;
110+
110111
out:
111112
put_handle(hdl);
113+
unlock(&hdl->lock);
114+
unlock(&g_process.fs_lock);
112115
unlock(&g_dcache_lock);
113116
return ret;
114117
}

libos/src/sys/libos_ioctl.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,11 @@ long libos_syscall_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) {
4141
if (!hdl)
4242
return -EBADF;
4343

44-
lock(&g_dcache_lock);
44+
lock(&g_dcache_lock); /* for dentry->inode */
45+
lock(&hdl->lock); /* for hdl->dentry */
4546
bool is_host_dev = hdl->type == TYPE_CHROOT && hdl->dentry->inode &&
4647
hdl->dentry->inode->type == S_IFCHR;
48+
unlock(&hdl->lock);
4749
unlock(&g_dcache_lock);
4850

4951
if (is_host_dev) {

libos/src/sys/libos_open.c

+4-6
Original file line numberDiff line numberDiff line change
@@ -373,15 +373,14 @@ static ssize_t do_getdents(int fd, uint8_t* buf, size_t buf_size, bool is_getden
373373
goto out_no_unlock;
374374
}
375375

376-
lock(&g_dcache_lock);
376+
lock(&g_dcache_lock); /* for dentry->inode */
377+
maybe_lock_pos_handle(hdl);
378+
lock(&hdl->lock); /* for hdl->dentry */
377379
if (!hdl->dentry->inode) {
378380
ret = -ENOENT;
379-
goto out_unlock_only_dcache_lock;
381+
goto out;
380382
}
381383

382-
maybe_lock_pos_handle(hdl);
383-
lock(&hdl->lock);
384-
385384
struct libos_dir_handle* dirhdl = &hdl->dir_info;
386385
if ((ret = populate_directory_handle(hdl)) < 0)
387386
goto out;
@@ -467,7 +466,6 @@ static ssize_t do_getdents(int fd, uint8_t* buf, size_t buf_size, bool is_getden
467466
out:
468467
unlock(&hdl->lock);
469468
maybe_unlock_pos_handle(hdl);
470-
out_unlock_only_dcache_lock:
471469
unlock(&g_dcache_lock);
472470
out_no_unlock:
473471
put_handle(hdl);

0 commit comments

Comments
 (0)