Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 24 Sep 2010 16:32:15 +0300
From:      Kostik Belousov <kostikbel@gmail.com>
To:        John Baldwin <jhb@freebsd.org>
Cc:        svn-src-head@freebsd.org, svn-src-all@freebsd.org, pluknet <pluknet@gmail.com>, src-committers@freebsd.org, Dag-Erling Smorgrav <des@freebsd.org>
Subject:   Re: svn commit: r212723 - head/sys/compat/linprocfs
Message-ID:  <20100924133215.GL34228@deviant.kiev.zoral.com.ua>
In-Reply-To: <201009240834.16786.jhb@freebsd.org>
References:  <201009160756.o8G7uZrg065332@svn.freebsd.org> <AANLkTi=20QDe6o2YxM8PTKOLXB3ZuxUCNQEPtWy9P4Rc@mail.gmail.com> <20100924115311.GH34228@deviant.kiev.zoral.com.ua> <201009240834.16786.jhb@freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help

--uwB7x3tnyrZQfZJI
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Fri, Sep 24, 2010 at 08:34:16AM -0400, John Baldwin wrote:
> On Friday, September 24, 2010 7:53:11 am Kostik Belousov wrote:
> > On Fri, Sep 24, 2010 at 02:17:29PM +0400, pluknet wrote:
> > > On 16 September 2010 11:56, Dag-Erling Smorgrav <des@freebsd.org> wro=
te:
> > > > Author: des
> > > > Date: Thu Sep 16 07:56:34 2010
> > > > New Revision: 212723
> > > > URL: http://svn.freebsd.org/changeset/base/212723
> > > >
> > > > Log:
> > > >  Implement proc/$$/environment.
> > > >
> > > [...]
> > >=20
> > > >  /*
> > > >  * Filler function for proc/pid/environ
> > > >  */
> > > >  static int
> > > >  linprocfs_doprocenviron(PFS_FILL_ARGS)
> > > >  {
> > > > +       int ret;
> > > >
> > > > -       sbuf_printf(sb, "doprocenviron\n%c", '\0');
> > > > -       return (0);
> > > > +       PROC_LOCK(p);
> > >=20
> > > With this change I observe the following sleepable after non-sleepabl=
e:
> > >=20
> > >  1st 0xffffff000290b558 process lock (process lock) @
> > > /usr/src/sys/modules/linprocfs/../../compat/linprocfs/linprocfs.c:1049
> > >  2nd 0xffffff00028f8848 user map (user map) @=20
> /usr/src/sys/vm/vm_map.c:3525
> > > KDB: stack backtrace:
> > > db_trace_self_wrapper() at db_trace_self_wrapper+0x2a
> > > _witness_debugger() at _witness_debugger+0x2e
> > > witness_checkorder() at witness_checkorder+0x807
> > > _sx_slock() at _sx_slock+0x55
> > > vm_map_lookup() at vm_map_lookup+0x55
> > > vm_fault() at vm_fault+0x113
> > > proc_rwmem() at proc_rwmem+0x7a
> > > linprocfs_doprocenviron() at linprocfs_doprocenviron+0x122
> > > pfs_read() at pfs_read+0x45b
> > > vn_read() at vn_read+0x256
> > > dofileread() at dofileread+0xa1
> > > kern_readv() at kern_readv+0x60
> > > read() at read+0x55
> > > syscallenter() at syscallenter+0x1aa
> > > syscall() at syscall+0x4c
> > > Xfast_syscall() at Xfast_syscall+0xe2
> > > --- syscall (3, FreeBSD ELF64, read), rip =3D 0x80074134c, rsp =3D
> > > 0x7fffffffe9c8, rbp =3D 0 ---
> > >=20
> > >=20
> > > > +
> > > > +       if ((ret =3D p_cansee(td, p)) !=3D 0) {
> > > > +               PROC_UNLOCK(p);
> > > > +               return ret;
> > > > +       }
> > > > +
> > > > +       ret =3D linprocfs_doargv(td, p, sb, ps_string_env);
> > > > +       PROC_UNLOCK(p);
> > > > +       return (ret);
> > > >  }
> >=20
> > This is easy to fix, isn't it ? But there seems to be much more nits.
> >=20
> > First, allocating 512 * sizeof(char *)-byte object on the stack is not
> > good.
> >=20
> > Second, the initialization of iov_len for reading the array
> > of string pointers misses '* sizeof(char *)'.
> >=20
> > And third (probably fatal) is the lack of checks that the end of
> > array and each string fits into the user portion of the map. I do not
> > see why addr that already has u_long type is casted to u_long. Also,
> > VM_MIN_ADDRESS, VM_MAXUSER_ADDRESS constants are for the native host
> > FreeBSD ABI, they may differ from the target process limits.
> >=20
> > Formatting is separate issue, let postpone it.
> >=20
> > diff --git a/sys/compat/linprocfs/linprocfs.c=20
> b/sys/compat/linprocfs/linprocfs.c
> > index c7fe158..fd62b1c 100644
> > --- a/sys/compat/linprocfs/linprocfs.c
> > +++ b/sys/compat/linprocfs/linprocfs.c
> > @@ -952,12 +952,9 @@ linprocfs_doargv(struct thread *td, struct proc *p=
,=20
> struct sbuf *sb,
> >  	struct uio tmp_uio;
> >  	struct ps_strings pss;
> >  	int ret, i, n_elements, found_end;
> > -	u_long addr;
> > -	char* env_vector[MAX_ARGV_STR];
> > +	u_long addr, pbegin;
> > +	char **env_vector;
> >  	char env_string[UIO_CHUNK_SZ];
> > -	char *pbegin;
> > -
> > -
> > =20
> >  #define	UIO_HELPER(uio, iov, base, len, cnt, offset, sz, flg, rw, td)	\
> >  do {									\
> > @@ -971,6 +968,10 @@ do {									\
> >  	uio.uio_rw =3D (rw); 						\
> >  	uio.uio_td =3D (td);						\
> >  } while (0)
> > +#define	VALID_USER_ADDR(addr)						\
> > +	((addr) >=3D p->p_sysent->sv_minuser && (addr) < p->p_sysent->sv_maxu=
ser)
> > +
> > +	env_vector =3D malloc(sizeof(char *) * MAX_ARGV_STR, M_TEMP, M_WAITOK=
);
> > =20
> >  	UIO_HELPER(tmp_uio, iov, &pss, sizeof(struct ps_strings), 1,
> >  	    (off_t)(p->p_sysent->sv_psstrings), sizeof(struct ps_strings),
> > @@ -978,37 +979,41 @@ do {									\
> > =20
> >  	ret =3D proc_rwmem(p, &tmp_uio);
> >  	if (ret !=3D 0)
> > -		return ret;
> > +		goto done;
> > =20
> >  	/* Get the array address and the number of elements */
> >  	resolver(pss, &addr, &n_elements);
> > =20
> >  	/* Consistent with lib/libkvm/kvm_proc.c */
> > -	if (n_elements > MAX_ARGV_STR || (u_long)addr < VM_MIN_ADDRESS ||
> > -    	    (u_long)addr >=3D VM_MAXUSER_ADDRESS) {
> > -		/* What error code should we return? */
> > -		return 0;
> > +	if (n_elements > MAX_ARGV_STR || !VALID_USER_ADDR(addr) ||
> > +	    !VALID_USER_ADDR(addr + MAX_ARGV_STR * sizeof(char *))) {
> > +		ret =3D EFAULT;
> > +		goto done;
> >  	}
> > =20
> > - 	UIO_HELPER(tmp_uio, iov, env_vector, MAX_ARGV_STR, 1,
> > + 	UIO_HELPER(tmp_uio, iov, env_vector, MAX_ARGV_STR * sizeof(char *), =
1,
> >  	    (vm_offset_t)(addr), iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
> > =20
> >  	ret =3D proc_rwmem(p, &tmp_uio);
> >  	if (ret !=3D 0)
> > -		return ret;
> > +		goto done;
> > =20
> >  	/* Now we can iterate through the list of strings */
> >  	for (i =3D 0; i < n_elements; i++) {
> >  	    found_end =3D 0;
> > -	    pbegin =3D env_vector[i];
> > -		while(!found_end) {
> > +	    pbegin =3D (vm_offset_t)env_vector[i];
> > +	    while (!found_end) {
> > +		    if (!VALID_USER_ADDR(pbegin) ||
> > +			!VALID_USER_ADDR(pbegin + sizeof(env_string))) {
> > +			    ret =3D EFAULT;
> > +			    goto done;
> > +		    }
> >  		    UIO_HELPER(tmp_uio, iov, env_string, sizeof(env_string), 1,
> > -			(vm_offset_t) pbegin, iov.iov_len, UIO_SYSSPACE,
> > -			UIO_READ, td);
> > +			pbegin, iov.iov_len, UIO_SYSSPACE, UIO_READ, td);
> > =20
> >  			ret =3D proc_rwmem(p, &tmp_uio);
> >  			if (ret !=3D 0)
> > -				return ret;
> > +				goto done;
> > =20
> >  			if (!strvalid(env_string, UIO_CHUNK_SZ)) {
> >  			    /*
> > @@ -1017,7 +1022,7 @@ do {									\
> >  			     * the pointer
> >  			     */
> >  			    sbuf_bcat(sb, env_string, UIO_CHUNK_SZ);
> > -			    pbegin =3D &(*pbegin) + UIO_CHUNK_SZ;
> > +			    pbegin +=3D UIO_CHUNK_SZ;
> >  			} else {
> >  			    found_end =3D 1;
> >  			}
> > @@ -1025,9 +1030,12 @@ do {									\
> >  		sbuf_printf(sb, "%s", env_string);
> >  	}
> > =20
> > +#undef VALID_USER_ADDR
> >  #undef UIO_HELPER
> > =20
> > -	return (0);
> > +done:
> > +	free(env_vector, M_TEMP);
> > +	return (ret);
> >  }
> > =20
> >  static void
> > @@ -1052,9 +1060,11 @@ linprocfs_doprocenviron(PFS_FILL_ARGS)
> >  		PROC_UNLOCK(p);
> >  		return ret;
> >  	}
> > +	_PHOLD(p);
> > +	PROC_UNLOCK(p);
> > =20
> >  	ret =3D linprocfs_doargv(td, p, sb, ps_string_env);
> > -	PROC_UNLOCK(p);
> > +	PRELE(p);
> >  	return (ret);
> >  }
>=20
> You need to add a P_WEXIT check here. _PHOLD() / PRELE() do not work
> once P_WEXIT is set (rather, exit1() may not notice and wait for a
> _PHOLD() invoked to drain once P_WEXIT is set).

Hmm, I think that PHOLD is not needed there, actually. Pseudofs
checks for exiting process in pfs_visible(_proc). Before the fill
method is called, process is held and unlocked. So my second _PHOLD
could be removed.

--uwB7x3tnyrZQfZJI
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (FreeBSD)

iEYEARECAAYFAkycqF4ACgkQC3+MBN1Mb4hZ1QCg40GXfKjzG0XjEh3fpgnA7jfx
nZsAoLHvgP7PAIIt+Zlyk5pURRuALy0K
=mp+o
-----END PGP SIGNATURE-----

--uwB7x3tnyrZQfZJI--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20100924133215.GL34228>