Date: Thu, 22 Jul 1999 02:22:32 +0200 (MET DST) From: Boris Nikolaus <boris@cs.tu-berlin.de> To: FreeBSD-gnats-submit@freebsd.org Subject: i386/12749: Bug in link() and all other filename functions in linux emulator Message-ID: <199907220022.CAA25908@kuerbis.cs.tu-berlin.de>
next in thread | raw e-mail | index | archive | help
>Number: 12749 >Category: i386 >Synopsis: Bug in link() and all other filename functions in linux emulator >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Wed Jul 21 17:30:00 PDT 1999 >Closed-Date: >Last-Modified: >Originator: Boris Nikolaus >Release: FreeBSD-current (22 Jul 1999) >Organization: >Environment: >Description: 1. The link() system call of the linux emulator does not perform filename translation (as symlink(), unlink(), ... do). 2. The filename translation functions do not check for enough memory when performing filename translation into the stack gap. 3. flock() doesn't check the type argument. 4. The linux emulator cannot handle long filenames. >How-To-Repeat: 1. Create /compat/linux/etc/dummy and try to call link("/etc/dummy", "/etc/dummy2") within the linux emulation mode. 2. Calling open() with a long filename (>256 chars) will overwrite the signal trampoline code and (if the filename is really long) the ps(1) information. 3. Try to call flock(fd, 4711); within the linux emulation mode. 4. After applying the patches, open() with long filenames will return ENAMETOOLONG. >Fix: 4. We should think about increasing SPARE_USRSPACE (/usr/include/sys/exec.h) to at least 2*(PATH_MAX+strlen("/compat/linux")) or use another method for filename translations. 1.+2.+3.: Apply the following patches in /usr/src/sys/i386/linux and call 'make install' in /usr/src/sys/modules/linux: *** linux_file.c.orig Thu Jul 22 01:07:02 1999 --- linux_file.c Thu Jul 22 00:45:42 1999 *************** *** 145,151 **** linux_pid_t l_pid; }; ! static void linux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock) { switch (linux_flock->l_type) { --- 145,151 ---- linux_pid_t l_pid; }; ! static int linux_to_bsd_flock(struct linux_flock *linux_flock, struct flock *bsd_flock) { switch (linux_flock->l_type) { *************** *** 158,168 **** --- 158,171 ---- case LINUX_F_UNLCK: bsd_flock->l_type = F_UNLCK; break; + default: + return EINVAL; } bsd_flock->l_whence = linux_flock->l_whence; bsd_flock->l_start = (off_t)linux_flock->l_start; bsd_flock->l_len = (off_t)linux_flock->l_len; bsd_flock->l_pid = (pid_t)linux_flock->l_pid; + return 0; } static void *************** *** 255,265 **** if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, sizeof(struct linux_flock)))) return error; ! linux_to_bsd_flock(&linux_flock, bsd_flock); fcntl_args.cmd = F_GETLK; fcntl_args.arg = (int)bsd_flock; ! error = fcntl(p, &fcntl_args); ! if (error) return error; bsd_to_linux_flock(bsd_flock, &linux_flock); return copyout((caddr_t)&linux_flock, (caddr_t)args->arg, --- 258,268 ---- if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, sizeof(struct linux_flock)))) return error; ! if ((error = linux_to_bsd_flock(&linux_flock, bsd_flock))) ! return error; fcntl_args.cmd = F_GETLK; fcntl_args.arg = (int)bsd_flock; ! if ((error = fcntl(p, &fcntl_args))) return error; bsd_to_linux_flock(bsd_flock, &linux_flock); return copyout((caddr_t)&linux_flock, (caddr_t)args->arg, *************** *** 269,275 **** if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, sizeof(struct linux_flock)))) return error; ! linux_to_bsd_flock(&linux_flock, bsd_flock); fcntl_args.cmd = F_SETLK; fcntl_args.arg = (int)bsd_flock; return fcntl(p, &fcntl_args); --- 272,279 ---- if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, sizeof(struct linux_flock)))) return error; ! if ((error = linux_to_bsd_flock(&linux_flock, bsd_flock))) ! return error; fcntl_args.cmd = F_SETLK; fcntl_args.arg = (int)bsd_flock; return fcntl(p, &fcntl_args); *************** *** 278,284 **** if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, sizeof(struct linux_flock)))) return error; ! linux_to_bsd_flock(&linux_flock, bsd_flock); fcntl_args.cmd = F_SETLKW; fcntl_args.arg = (int)bsd_flock; return fcntl(p, &fcntl_args); --- 282,289 ---- if ((error = copyin((caddr_t)args->arg, (caddr_t)&linux_flock, sizeof(struct linux_flock)))) return error; ! if ((error = linux_to_bsd_flock(&linux_flock, bsd_flock))) ! return error; fcntl_args.cmd = F_SETLKW; fcntl_args.arg = (int)bsd_flock; return fcntl(p, &fcntl_args); *************** *** 592,597 **** --- 597,622 ---- bsd.flags = args->flags; return access(p, &bsd); + } + + int + linux_link(struct proc *p, struct linux_link_args *args) + { + struct link_args bsd; + caddr_t sg; + + sg = stackgap_init(); + CHECKALTEXIST(p, &sg, args->path); + CHECKALTCREAT(p, &sg, args->to); + + #ifdef DEBUG + printf("Linux-emul(%d): link(%s, %s)\n", + p->p_pid, args->path, args->to); + #endif + bsd.path = args->path; + bsd.link = args->to; + + return link(p, &bsd); } int *** linux_misc.c.orig Thu Jul 22 01:07:16 1999 --- linux_misc.c Thu Jul 22 01:15:32 1999 *************** *** 173,180 **** vp = NULL; NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, args->library, p); ! error = namei(&ni); ! if (error) goto cleanup; vp = ni.ni_vp; --- 173,179 ---- vp = NULL; NDINIT(&ni, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, args->library, p); ! if ((error = namei(&ni))) goto cleanup; vp = ni.ni_vp; *************** *** 199,206 **** /* * Executable? */ ! error = VOP_GETATTR(vp, &attr, p->p_ucred, p); ! if (error) goto cleanup; if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || --- 198,204 ---- /* * Executable? */ ! if ((error = VOP_GETATTR(vp, &attr, p->p_ucred, p))) goto cleanup; if ((vp->v_mount->mnt_flag & MNT_NOEXEC) || *************** *** 221,232 **** /* * Can we access it? */ ! error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p); ! if (error) goto cleanup; ! error = VOP_OPEN(vp, FREAD, p->p_ucred, p); ! if (error) goto cleanup; /* --- 219,228 ---- /* * Can we access it? */ ! if ((error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p))) goto cleanup; ! if ((error = VOP_OPEN(vp, FREAD, p->p_ucred, p))) goto cleanup; /* *************** *** 776,789 **** printf("Linux-emul(%d): pipe(*)\n", p->p_pid); #endif reg_edx = p->p_retval[1]; ! error = pipe(p, 0); ! if (error) { p->p_retval[1] = reg_edx; return error; } ! error = copyout(p->p_retval, args->pipefds, 2*sizeof(int)); ! if (error) { p->p_retval[1] = reg_edx; return error; } --- 772,783 ---- printf("Linux-emul(%d): pipe(*)\n", p->p_pid); #endif reg_edx = p->p_retval[1]; ! if ((error = pipe(p, 0))) { p->p_retval[1] = reg_edx; return error; } ! if ((error = copyout(p->p_retval, args->pipefds, 2*sizeof(int)))) { p->p_retval[1] = reg_edx; return error; } *************** *** 916,921 **** --- 910,917 ---- tv[1].tv_usec = 0; /* so that utimes can copyin */ tvp = (struct timeval *)stackgap_alloc(&sg, sizeof(tv)); + if (!tvp) + return ENAMETOOLONG; if ((error = copyout(tv, tvp, sizeof(tv)))) return error; bsdutimes.tptr = tvp; *** linux_proto.h.orig Thu Jul 22 01:07:19 1999 --- linux_proto.h Thu Jul 22 00:40:20 1999 *************** *** 35,40 **** --- 35,44 ---- char * path; char path_[PAD_(char *)]; int mode; char mode_[PAD_(int)]; }; + struct linux_link_args { + char * path; char path_[PAD_(char *)]; + char * to; char to_[PAD_(char *)]; + }; struct linux_unlink_args { char * path; char path_[PAD_(char *)]; }; *************** *** 392,397 **** --- 396,402 ---- int linux_open __P((struct proc *, struct linux_open_args *)); int linux_waitpid __P((struct proc *, struct linux_waitpid_args *)); int linux_creat __P((struct proc *, struct linux_creat_args *)); + int linux_link __P((struct proc *, struct linux_link_args *)); int linux_unlink __P((struct proc *, struct linux_unlink_args *)); int linux_execve __P((struct proc *, struct linux_execve_args *)); int linux_chdir __P((struct proc *, struct linux_chdir_args *)); *** linux_syscall.h.orig Thu Jul 22 01:07:29 1999 --- linux_syscall.h Thu Jul 22 00:40:28 1999 *************** *** 14,20 **** #define LINUX_SYS_close 6 #define LINUX_SYS_linux_waitpid 7 #define LINUX_SYS_linux_creat 8 ! #define LINUX_SYS_link 9 #define LINUX_SYS_linux_unlink 10 #define LINUX_SYS_linux_execve 11 #define LINUX_SYS_linux_chdir 12 --- 14,20 ---- #define LINUX_SYS_close 6 #define LINUX_SYS_linux_waitpid 7 #define LINUX_SYS_linux_creat 8 ! #define LINUX_SYS_linux_link 9 #define LINUX_SYS_linux_unlink 10 #define LINUX_SYS_linux_execve 11 #define LINUX_SYS_linux_chdir 12 *** linux_sysent.c.orig Thu Jul 22 01:07:31 1999 --- linux_sysent.c Thu Jul 22 00:40:32 1999 *************** *** 23,29 **** { 1, (sy_call_t *)close }, /* 6 = close */ { 3, (sy_call_t *)linux_waitpid }, /* 7 = linux_waitpid */ { 2, (sy_call_t *)linux_creat }, /* 8 = linux_creat */ ! { 2, (sy_call_t *)link }, /* 9 = link */ { 1, (sy_call_t *)linux_unlink }, /* 10 = linux_unlink */ { 3, (sy_call_t *)linux_execve }, /* 11 = linux_execve */ { 1, (sy_call_t *)linux_chdir }, /* 12 = linux_chdir */ --- 23,29 ---- { 1, (sy_call_t *)close }, /* 6 = close */ { 3, (sy_call_t *)linux_waitpid }, /* 7 = linux_waitpid */ { 2, (sy_call_t *)linux_creat }, /* 8 = linux_creat */ ! { 2, (sy_call_t *)linux_link }, /* 9 = linux_link */ { 1, (sy_call_t *)linux_unlink }, /* 10 = linux_unlink */ { 3, (sy_call_t *)linux_execve }, /* 11 = linux_execve */ { 1, (sy_call_t *)linux_chdir }, /* 12 = linux_chdir */ *** linux_util.c.orig Thu Jul 22 01:07:37 1999 --- linux_util.c Thu Jul 22 00:40:37 1999 *************** *** 159,166 **** *pbuf = buf; else { sz = &ptr[len] - buf; ! *pbuf = stackgap_alloc(sgp, sz + 1); ! error = copyout(buf, *pbuf, sz); free(buf, M_TEMP); } --- 159,172 ---- *pbuf = buf; else { sz = &ptr[len] - buf; ! if (!(ptr = stackgap_alloc(sgp, sz))) { ! error = ENAMETOOLONG; ! goto bad; ! } ! if ((error = copyout(buf, ptr, sz))) { ! goto bad; ! } ! *pbuf = ptr; free(buf, M_TEMP); } *** linux_util.h.orig Thu Jul 22 01:07:38 1999 --- linux_util.h Thu Jul 22 00:40:40 1999 *************** *** 54,68 **** #endif static __inline caddr_t stackgap_init(void); static __inline void *stackgap_alloc(caddr_t *, size_t); static __inline caddr_t stackgap_init() { - #define szsigcode (*(curproc->p_sysent->sv_szsigcode)) return (caddr_t)(PS_STRINGS - szsigcode - SPARE_USRSPACE); } static __inline void * stackgap_alloc(sgp, sz) --- 54,75 ---- #endif static __inline caddr_t stackgap_init(void); + static __inline caddr_t stackgap_end(void); static __inline void *stackgap_alloc(caddr_t *, size_t); + #define szsigcode (*(curproc->p_sysent->sv_szsigcode)) + static __inline caddr_t stackgap_init() { return (caddr_t)(PS_STRINGS - szsigcode - SPARE_USRSPACE); } + static __inline caddr_t + stackgap_end() + { + return (caddr_t)(PS_STRINGS - szsigcode); + } static __inline void * stackgap_alloc(sgp, sz) *************** *** 71,76 **** --- 78,85 ---- { void *p = (void *) *sgp; *sgp += ALIGN(sz); + if (*sgp > stackgap_end()) + return NULL; return p; } *** syscalls.master.orig Thu Jul 22 01:07:42 1999 --- syscalls.master Thu Jul 22 00:40:45 1999 *************** *** 40,46 **** 6 NOPROTO LINUX { int close(int fd); } 7 STD LINUX { int linux_waitpid(int pid, int *status, int options);} 8 STD LINUX { int linux_creat(char *path, int mode); } ! 9 NOPROTO LINUX { int link(char *path, char *link); } 10 STD LINUX { int linux_unlink(char *path); } 11 STD LINUX { int linux_execve(char *path, char **argp, char **envp); } 12 STD LINUX { int linux_chdir(char *path); } --- 40,46 ---- 6 NOPROTO LINUX { int close(int fd); } 7 STD LINUX { int linux_waitpid(int pid, int *status, int options);} 8 STD LINUX { int linux_creat(char *path, int mode); } ! 9 STD LINUX { int linux_link(char *path, char *to); } 10 STD LINUX { int linux_unlink(char *path); } 11 STD LINUX { int linux_execve(char *path, char **argp, char **envp); } 12 STD LINUX { int linux_chdir(char *path); } >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199907220022.CAA25908>