Index: sys/compat/linux/linux_misc.c =================================================================== --- sys/compat/linux/linux_misc.c +++ sys/compat/linux/linux_misc.c @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -2253,23 +2254,33 @@ linux_sched_getaffinity(struct thread *td, struct linux_sched_getaffinity_args *args) { - int error; struct thread *tdt; + cpuset_t *mask; + size_t size; + id_t tid; + int error; - if (args->len < sizeof(cpuset_t)) + if (!__is_aligned(args->len, sizeof(l_ulong))) + return (EINVAL); + if (args->len * NBBY < smp_cpus) return (EINVAL); - tdt = linux_tdfind(td, args->pid, -1); if (tdt == NULL) return (ESRCH); - + tid = tdt->td_tid; PROC_UNLOCK(tdt->td_proc); - error = kern_cpuset_getaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID, - tdt->td_tid, sizeof(cpuset_t), (cpuset_t *)args->user_mask_ptr); - if (error == 0) - td->td_retval[0] = sizeof(cpuset_t); + size = min(args->len, sizeof(cpuset_t)); + mask = malloc(sizeof(cpuset_t), M_LINUX, M_WAITOK | M_ZERO); + error = kern_cpuset_getaffinity_raw(td, + CPU_LEVEL_WHICH, CPU_WHICH_TID, tid, mask); + if (error == 0) { + error = copyout(mask, args->user_mask_ptr, size); + if (error == 0) + td->td_retval[0] = size; + } + free(mask, M_LINUX); return (error); } @@ -2281,18 +2292,34 @@ struct linux_sched_setaffinity_args *args) { struct thread *tdt; - - if (args->len < sizeof(cpuset_t)) - return (EINVAL); + cpuset_t *mask; + size_t size; + id_t tid; + int error; tdt = linux_tdfind(td, args->pid, -1); if (tdt == NULL) return (ESRCH); - + if (p_candebug(td, tdt->td_proc) != 0) { + PROC_UNLOCK(tdt->td_proc); + return (EPERM); + } + tid = tdt->td_tid; PROC_UNLOCK(tdt->td_proc); - return (kern_cpuset_setaffinity(td, CPU_LEVEL_WHICH, CPU_WHICH_TID, - tdt->td_tid, sizeof(cpuset_t), (cpuset_t *) args->user_mask_ptr)); + mask = malloc(sizeof(cpuset_t), M_LINUX, M_WAITOK | M_ZERO); + size = min(args->len, howmany(smp_cpus, NBBY)); + size = min(size, sizeof(cpuset_t)); + error = copyin(args->user_mask_ptr, mask, size); + if (error == 0) { + error = kern_cpuset_setaffinity_raw(td, + CPU_LEVEL_WHICH, CPU_WHICH_TID, tid, sizeof(cpuset_t), mask); + if (error == EDEADLK) + error = EINVAL; + } + + free(mask, M_LINUX); + return (error); } struct linux_rlimit64 {