summaryrefslogtreecommitdiffstats
path: root/sys/compat/linux/linux_misc.c
diff options
context:
space:
mode:
authornetchild <netchild@FreeBSD.org>2006-12-02 14:56:25 +0000
committernetchild <netchild@FreeBSD.org>2006-12-02 14:56:25 +0000
commit2db40ccfce7ea070a08fa10f3969ee21f4d49779 (patch)
tree12cfdac707eb1c777faf6a99820a9d9176a76fdc /sys/compat/linux/linux_misc.c
parent1cfd0ae28fc82197d5129459391224f42bc78cd5 (diff)
downloadFreeBSD-src-2db40ccfce7ea070a08fa10f3969ee21f4d49779.zip
FreeBSD-src-2db40ccfce7ea070a08fa10f3969ee21f4d49779.tar.gz
MFP4 (108673, 110519, 110874):
- Currently LINUX_MAX_COMM_LEN is smaller than MAXCOMLEN, but in case this will change we have a buffer overflow. Apply some defensive programming to DTRT when this should happen. - Use copyinstr() instead of copyin where appropriate. * Fallback to copyin() in case of ENAMETOOLONG. [1] * Use the right source and destination (it was wrong before). - Use strlcpy instead of strcpy. - Properly lock the read case (PR_GET_NAME) like the write case. Reviewed by: rwatson (except [1]) Suggested by: rwatson [1]
Diffstat (limited to 'sys/compat/linux/linux_misc.c')
-rw-r--r--sys/compat/linux/linux_misc.c35
1 files changed, 30 insertions, 5 deletions
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index c7ace44..10b0ad0 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -1588,7 +1588,7 @@ linux_exit_group(struct thread *td, struct linux_exit_group_args *args)
int
linux_prctl(struct thread *td, struct linux_prctl_args *args)
{
- int error = 0;
+ int error = 0, max_size;
struct proc *p = td->td_proc;
char comm[LINUX_MAX_COMM_LEN];
struct linux_emuldata *em;
@@ -1615,16 +1615,41 @@ linux_prctl(struct thread *td, struct linux_prctl_args *args)
EMUL_UNLOCK(&emul_lock);
break;
case LINUX_PR_SET_NAME:
- comm[LINUX_MAX_COMM_LEN-1] = 0;
- error = copyin(comm, (void *)(register_t) args->arg2, LINUX_MAX_COMM_LEN-1);
+ /*
+ * To be on the safe side we need to make sure to not
+ * overflow the size a linux program expects. We already
+ * do this here in the copyin, so that we don't need to
+ * check on copyout.
+ */
+ max_size = MIN(sizeof(comm), sizeof(p->p_comm));
+ error = copyinstr((void *)(register_t) args->arg2, comm,
+ max_size, NULL);
+
+ /* Linux silently truncates the name if it is too long. */
+ if (error == ENAMETOOLONG) {
+ /*
+ * XXX: copyinstr() isn't documented to populate the
+ * array completely, so do a copyin() to be on the
+ * safe side. This should be changed in case
+ * copyinstr() is changed to guarantee this.
+ */
+ error = copyin((void *)(register_t)args->arg2, comm,
+ max_size - 1);
+ comm[max_size - 1] = '\0';
+ }
if (error)
return (error);
+
PROC_LOCK(p);
- strcpy(p->p_comm, comm);
+ strlcpy(p->p_comm, comm, sizeof(p->p_comm));
PROC_UNLOCK(p);
break;
case LINUX_PR_GET_NAME:
- error = copyout(&p->p_comm, (void *)(register_t) args->arg2, MAXCOMLEN+1);
+ PROC_LOCK(p);
+ strlcpy(comm, p->p_comm, sizeof(comm));
+ PROC_UNLOCK(p);
+ error = copyout(comm, (void *)(register_t) args->arg2,
+ strlen(comm)+1);
break;
default:
error = EINVAL;
OpenPOWER on IntegriCloud