/* Read-modify-write a semaphore in an arbitrary task, usually +/- 1. */ static int stapiu_write_task_semaphore(struct task_struct* task, unsigned long addr, unsigned short delta) { int count, rc = 0; unsigned short sdt_semaphore = 0; /* NB: fixed size */ /* XXX: need to analyze possibility of race condition */ count = __access_process_vm_noflush(task, addr, &sdt_semaphore, sizeof(sdt_semaphore), 0); if (count != sizeof(sdt_semaphore)) rc = 1; else { sdt_semaphore += delta; count = __access_process_vm_noflush(task, addr, &sdt_semaphore, sizeof(sdt_semaphore), 1); rc = (count == sizeof(sdt_semaphore)) ? 0 : 1; } return rc; }
static int _stp_build_id_check (struct _stp_module *m, unsigned long notes_addr, struct task_struct *tsk) { int j; for (j = 0; j < m->build_id_len; j++) { /* Use set_fs / get_user to access conceivably invalid addresses. * If loc2c-runtime.h were more easily usable, a deref() loop * could do it too. */ mm_segment_t oldfs = get_fs(); int rc; unsigned char theory, practice = 0; #ifdef STAPCONF_PROBE_KERNEL if (!tsk) { theory = m->build_id_bits[j]; set_fs(KERNEL_DS); rc = probe_kernel_read(&practice, (void*)(notes_addr + j), 1); } else #endif { theory = m->build_id_bits[j]; set_fs (tsk ? USER_DS : KERNEL_DS); /* * Why check CONFIG_UTRACE here? If we're using real in-kernel * utrace, we can always just call get_user() (since we're * either reading kernel memory or tsk == current). * * Since we're only reading here, we can call * __access_process_vm_noflush(), which only calls things that * are exported. */ #ifdef CONFIG_UTRACE rc = get_user(practice, ((unsigned char*)(void*)(notes_addr + j))); #else if (!tsk || tsk == current) { rc = get_user(practice, ((unsigned char*)(void*)(notes_addr + j))); } else { rc = (__access_process_vm_noflush(tsk, (notes_addr + j), &practice, 1, 0) != 1); } #endif } set_fs(oldfs); if (rc || (theory != practice)) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) _stp_error ("Build-id mismatch [man error::buildid]: \"%s\" byte %d (0x%02x vs 0x%02x) address %#lx rc %d\n", m->path, j, theory, practice, notes_addr, rc); return 1; #else /* This branch is a surrogate for kernels affected by Fedora bug * #465873. */ _stp_warn (KERN_WARNING "Build-id mismatch [man error::buildid]: \"%s\" byte %d (0x%02x vs 0x%02x) rc %d\n", m->path, j, theory, practice, rc); #endif break; } /* end mismatch */ } /* end per-byte check loop */ return 0; }
static void _stp_vma_match_vdso(struct task_struct *tsk) { /* vdso is arch specific */ #if defined(STAPCONF_MM_CONTEXT_VDSO) || defined(STAPCONF_MM_CONTEXT_VDSO_BASE) int i, j; if (tsk->mm) { struct _stp_module *found = NULL; #ifdef STAPCONF_MM_CONTEXT_VDSO unsigned long vdso_addr = (unsigned long) tsk->mm->context.vdso; #else unsigned long vdso_addr = tsk->mm->context.vdso_base; #endif dbug_task_vma(1,"tsk: %d vdso: 0x%lx\n", tsk->pid, vdso_addr); for (i = 0; i < _stp_num_modules && found == NULL; i++) { struct _stp_module *m = _stp_modules[i]; if (m->path[0] == '/' && m->num_sections == 1 && strncmp(m->name, "vdso", 4) == 0) { unsigned long notes_addr; int all_ok = 1; notes_addr = vdso_addr + m->build_id_offset; dbug_task_vma(1,"notes_addr %s: 0x%lx + 0x%lx = 0x%lx (len: %x)\n", m->path, vdso_addr, m->build_id_offset, notes_addr, m->build_id_len); for (j = 0; j < m->build_id_len; j++) { int rc; unsigned char b; /* * Why check CONFIG_UTRACE here? If we're using real * in-kernel utrace, we can always just call * get_user() (since tsk == current). * * Since we're only reading here, we can call * __access_process_vm_noflush(), which only calls * things that are exported. */ #ifdef CONFIG_UTRACE rc = copy_from_user(&b, (void*)(notes_addr + j), 1); #else if (tsk == current) { rc = copy_from_user(&b, (void*)(notes_addr + j), 1); } else { rc = (__access_process_vm_noflush(tsk, (notes_addr + j), &b, 1, 0) != 1); } #endif if (rc || b != m->build_id_bits[j]) { dbug_task_vma(1,"darn, not equal (rc=%d) at %d (0x%x != 0x%x)\n", rc, j, b, m->build_id_bits[j]); all_ok = 0; break; } } if (all_ok) found = m; } } if (found != NULL) { stap_add_vma_map_info(tsk, vdso_addr, vdso_addr + found->sections[0].size, "vdso", found); dbug_task_vma(1,"found vdso: %s\n", found->path); } } #endif /* STAPCONF_MM_CONTEXT_VDSO */ }