Skip site navigation (1)Skip section navigation (2)
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>