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]
This commit is contained in:
netchild 2006-12-02 14:56:25 +00:00
parent 1cfd0ae28f
commit 2db40ccfce

View File

@ -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;