-
Notifications
You must be signed in to change notification settings - Fork 57
LATX, fix: fix getdents64 interference with /proc/[pid]/task #228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -14218,35 +14218,125 @@ static abi_long do_syscall1(void *cpu_env, int num, abi_long arg1, | |||||||||||||||||||||||||||||||||
| #endif /* TARGET_NR_getdents */ | ||||||||||||||||||||||||||||||||||
| #if defined(TARGET_NR_getdents64) && defined(__NR_getdents64) | ||||||||||||||||||||||||||||||||||
| case TARGET_NR_getdents64: | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| struct linux_dirent64 *dirp; | ||||||||||||||||||||||||||||||||||
| abi_long count = arg3; | ||||||||||||||||||||||||||||||||||
| if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) | ||||||||||||||||||||||||||||||||||
| return -TARGET_EFAULT; | ||||||||||||||||||||||||||||||||||
| ret = get_errno(sys_getdents64(arg1, dirp, count)); | ||||||||||||||||||||||||||||||||||
| if (!is_error(ret)) { | ||||||||||||||||||||||||||||||||||
| struct linux_dirent64 *de; | ||||||||||||||||||||||||||||||||||
| int len = ret; | ||||||||||||||||||||||||||||||||||
| int reclen; | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| char proc_path[PATH_MAX]; | ||||||||||||||||||||||||||||||||||
| char real_path[PATH_MAX]; | ||||||||||||||||||||||||||||||||||
| int fd = arg1; | ||||||||||||||||||||||||||||||||||
| bool is_task_dir = false; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", fd); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| ssize_t path_len = readlink(proc_path, real_path, sizeof(real_path) - 1); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (path_len > 0) { | ||||||||||||||||||||||||||||||||||
| real_path[path_len] = '\0'; | ||||||||||||||||||||||||||||||||||
| int pid; | ||||||||||||||||||||||||||||||||||
| char extra[2]; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (sscanf(real_path, "/proc/%d/task%1s", &pid, extra) == 1) { | ||||||||||||||||||||||||||||||||||
| #ifdef CONFIG_LATX_DEBUG | ||||||||||||||||||||||||||||||||||
| fprintf(stderr, "latx: Detected task directory: %s\n", real_path); | ||||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||||
| is_task_dir = true; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| struct linux_dirent64 *dirp; | ||||||||||||||||||||||||||||||||||
| abi_long count = arg3; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (!(dirp = lock_user(VERIFY_WRITE, arg2, count, 0))) | ||||||||||||||||||||||||||||||||||
| return -TARGET_EFAULT; | ||||||||||||||||||||||||||||||||||
| ret = get_errno(sys_getdents64(arg1, dirp, count)); | ||||||||||||||||||||||||||||||||||
| if (!is_error(ret)) { | ||||||||||||||||||||||||||||||||||
| struct linux_dirent64 *de; | ||||||||||||||||||||||||||||||||||
| int len = ret; | ||||||||||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||||||||||
| * Filter ghost threads only for /proc/<pid>/task | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| if (is_task_dir) { | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| int valid_tids[512]; | ||||||||||||||||||||||||||||||||||
| int valid_count = 0; | ||||||||||||||||||||||||||||||||||
| CPUState *cpu_iter; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| CPU_FOREACH(cpu_iter) { | ||||||||||||||||||||||||||||||||||
| TaskState *ts = (TaskState *)cpu_iter->opaque; | ||||||||||||||||||||||||||||||||||
| if (ts && valid_count < 512) { | ||||||||||||||||||||||||||||||||||
| valid_tids[valid_count++] = ts->ts_tid; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+14261
to
+14267
|
||||||||||||||||||||||||||||||||||
| CPU_FOREACH(cpu_iter) { | |
| TaskState *ts = (TaskState *)cpu_iter->opaque; | |
| if (ts && valid_count < 512) { | |
| valid_tids[valid_count++] = ts->ts_tid; | |
| } | |
| } | |
| cpu_list_lock(); | |
| CPU_FOREACH(cpu_iter) { | |
| TaskState *ts = (TaskState *)cpu_iter->opaque; | |
| if (ts && valid_count < 512) { | |
| valid_tids[valid_count++] = ts->ts_tid; | |
| } | |
| } | |
| cpu_list_unlock(); |
Copilot
AI
Jan 23, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The task_dir filtering path does not perform the necessary byte-swapping operations on dirent64 fields. Looking at lines 14174-14180, the else branch performs tswap16 on d_reclen, tswap64s on d_ino and d_off, and conditional tswap32 for 32-bit targets. These byte-swap operations are necessary for correct cross-architecture emulation. The task_dir path should apply the same byte-swapping to the remaining entries after filtering.
| /* Byte-swap dirent fields for target, mirroring non-task_dir path */ | |
| de->d_reclen = tswap16(reclen); | |
| tswap64s((uint64_t *)&de->d_ino); | |
| tswap64s((uint64_t *)&de->d_off); | |
| #if TARGET_ABI_BITS == 32 | |
| de->d_off = (int32_t)de->d_off; /* int32; Fix for ext4 filesystem */ | |
| de->d_ino = tswap32(de->d_ino); /* uint32; Fix for ext4 filesystem */ | |
| #endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hard-coded array size of 512 may be insufficient for systems with many threads and could lead to silent truncation of the valid TID list. If the number of threads exceeds 512, some valid threads will not be included in valid_tids, causing them to be incorrectly hidden from /proc/[pid]/task listings. Consider using a dynamic allocation approach or defining this as a constant with appropriate documentation of its limits.