From ino-news@kabelmail.de  Thu Jun 26 14:07:46 2008
Return-Path: <ino-news@kabelmail.de>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id E3BFE106567C
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 26 Jun 2008 14:07:46 +0000 (UTC)
	(envelope-from ino-news@kabelmail.de)
Received: from smtpa.mediabeam.com (smtpa1.mediabeam.com [194.25.41.13])
	by mx1.freebsd.org (Postfix) with ESMTP id 351158FC23
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 26 Jun 2008 14:07:45 +0000 (UTC)
	(envelope-from ino-news@kabelmail.de)
Received: from spotteswoode.dnsalias.org (91-64-207-64-dynip.superkabel.de [91.64.207.64])
	(authenticated bits=0)
	by smtpa.mediabeam.com (8.13.0/8.13.1) with ESMTP id m5QDuIot029411
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 26 Jun 2008 15:56:18 +0200
Received: by spotteswoode.dnsalias.org (Postfix, from userid 0)
	id D669F371D8; Thu, 26 Jun 2008 15:55:49 +0200 (CEST)
Message-Id: <20080626135549.D669F371D8@spotteswoode.dnsalias.org>
Date: Thu, 26 Jun 2008 15:55:49 +0200 (CEST)
From: clemens fischer <ino-news@spotteswoode.dnsalias.org>
Reply-To: clemens fischer <ino-news@spotteswoode.dnsalias.org>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: access(2) grants root execute perms for non-executable files
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         125009
>Category:       kern
>Synopsis:       [patch] access(2) grants root execute perms for non-executable files
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    jh
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jun 26 14:10:04 UTC 2008
>Closed-Date:    Fri Sep 10 05:13:30 UTC 2010
>Last-Modified:  Fri Sep 10 05:13:30 UTC 2010
>Originator:     clemens fischer <ino-news@spotteswoode.dnsalias.org>
>Release:        FreeBSD 8.0-CURRENT i386
>Organization:
>Environment:
System: FreeBSD spotteswoode.dnsalias.org 8.0-CURRENT FreeBSD 8.0-CURRENT #21: Mon Jun 23 20:24:05 CEST 2008 root@spotteswoode.dnsalias.org:/usr/obj/usr/src/sys/spott_fbsd8_i386 i386

>Description:

i found the problem when trying out "git" (the VCS).  per default,
git-init(1) creates repos containing eg. pre-commit hooks, shell scripts
to verify commits etc.  they are mode 0644 or mode 0664 and can be
changed by the user.  to enable them, one has to "chmod +x" them.

unprivileged users can use (newer) git-releases without worrying about
this, but if root wants to operate a git repo, every commit aborts with
messages like: "fatal: exec .../.git/hooks/prepare-commit-msg failed."
for every hook involved.

after "ktrace git-commit", kdump(1) shows:

: 73042 git-commit CALL  access(0x8123320,X_OK)
: 73042 git-commit NAMI  "/home/src/bulk/ion/.git/hooks/prepare-commit-msg"
: 73042 git-commit RET   access 0
: 73042 git-commit CALL  fork
: 73042 git-commit RET   fork 73043/0x11d53
: 73043 git-commit RET   fork 0
: 73043 git-commit CALL  open(0x80f1b83,O_RDWR,<unused>0)
: 73043 git-commit NAMI  "/dev/null"
: 73042 git-commit CALL  wait4(0x11d53,0xbfbfd2cc,<invalid>0,0)
: 73043 git-commit RET   open 3
: 73043 git-commit CALL  dup2(0x3,0)
: 73043 git-commit RET   dup2 0
: 73043 git-commit CALL  close(0x3)
: 73043 git-commit RET   close 0
: 73043 git-commit CALL  dup2(0x2,0x1)
: 73043 git-commit RET   dup2 1
: 73043 git-commit CALL  execve(0x8123320,0xbfbfd728,0x8213400)
: 73043 git-commit NAMI  "/home/src/bulk/ion/.git/hooks/prepare-commit-msg"
: 73043 git-commit RET   execve -1 errno 13 Permission denied
: 73043 git-commit CALL  stat(0x8123320,0xbfbfcdf8)
: 73043 git-commit NAMI  "/home/src/bulk/ion/.git/hooks/prepare-commit-msg"
: 73043 git-commit STRU  struct stat {dev=117, ino=800809, mode=-rw-r--r-- , nlink=1, uid=0, gid=0, rdev=3262495, atime=1214332267, stime=1214331402, ctime=1214331402, birthtime=1214331402, size=1196, blksize=4096, blocks=4, flags=0x0 }
: 73043 git-commit RET   stat 0
: 73043 git-commit CALL  write(0x2,0xbfbfca38,0x45)
: 73043 git-commit GIO   fd 2 wrote 69 bytes
:       "fatal: exec /home/src/bulk/ion/.git/hooks/prepare-commit-msg failed.
:       "

i verified this in the current git source:  in
git/builtin-commit.c::run_hook() there's the sequence:

: if (access(argv[0], X_OK) < 0)
:   return 0;
:
: memset(&hook, 0, sizeof(hook));
: hook.argv = argv;
: hook.no_stdin = 1;
: hook.stdout_to_stderr = 1;
: hook.env = env;
:
: return run_command(&hook);

this check works correctly for non-root, but any file accessible in
any way for root _passes_ the "(access(argv[0], X_OK) < 0)" check, a
subsequent execvp(3) fails.  doing "git-init; date > fileA; git-commit
-a" as a non-privileged user works as expected.

but this isn't a git-problem anyway:  i took
/usr/src/tools/regression/security/access/* and changed every check for
"access(path, R_OK)" into "access(path, X_OK)".  as the test files in
this test are created modes 0400 and 0040, one would expect every check
to fail when using X_OK, but the output is:

: /src/localcode/test/access
: 0  # ./testaccess
: Effective uid was used instead of real uid in access().
: Effective gid was used instead of real gid in access().
: 2 errors seen.


>How-To-Repeat:

you can either install ports/devel/git and do:

: git-init
: date > fileA
: git-add fileA
: git-commit

as 1) root and 2) somebody_else and watch the difference:

: (1) "fatal: exec /tmp/.git/hooks/pre-commit failed."

: (2) "Created initial commit..."

-or-

you could apply the following patch in
/usr/src/tools/regression/security/access/, and do "make; ./testaccess":

: /src/localcode/test/access
: 0  # ./testaccess
: Effective uid was used instead of real uid in access().
: Effective gid was used instead of real gid in access().
: 2 errors seen.

i'd expect each and every test to fail as none of the test files is
executable!

pseudo-patch replacing R_OK with X_OK (only for testing!):

: /src/localcode/test/access
: 0  # hg diff
: diff --git a/access/testaccess.c b/access/testaccess.c
: --- a/access/testaccess.c
: +++ b/access/testaccess.c
: @@ -216,14 +216,14 @@
:
:         errorseen = 0;
:
: -       error = access("test1", R_OK);
: +       error = access("test1", /*R_OK*/ X_OK);
:         if (!error) {
:                 fprintf(stderr, "saved uid used instead of real uid\n");
:                 errorseen++;
:         }
:
:  #ifdef EACCESS_AVAILABLE
: -       error = eaccess("test1", R_OK);
: +       error = eaccess("test1", /*R_OK*/ X_OK);
:         if (!error) {
:                 fprintf(stderr, "saved uid used instead of effective uid\n");
:                 errorseen++;
: @@ -245,7 +245,7 @@
:         }
:
:         /* Check that the real uid is used, not the effective uid */
: -       error = access("test2", R_OK);
: +       error = access("test2", /*R_OK*/ X_OK);
:         if (error) {
:                 fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
:                 errorseen++;
: @@ -253,7 +253,7 @@
:
:  #ifdef EACCESS_AVAILABLE
:         /* Check that the effective uid is used, not the real uid */
: -       error = eaccess("test3", R_OK);
: +       error = eaccess("test3", /*R_OK*/ X_OK);
:         if (error) {
:                 fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
:                 errorseen++;
: @@ -261,7 +261,7 @@
:  #endif
:
:         /* Check that the real uid is used, not the effective uid */
: -       error = access("test3", R_OK);
: +       error = access("test3", /*R_OK*/ X_OK);
:         if (!error) {
:                 fprintf(stderr, "Effective uid was used instead of real uid in access().\n");
:                 errorseen++;
: @@ -269,7 +269,7 @@
:
:  #ifdef EACCESS_AVAILABLE
:         /* Check that the effective uid is used, not the real uid */
: -       error = eaccess("test2", R_OK);
: +       error = eaccess("test2", /*R_OK*/ X_OK);
:         if (!error) {
:                 fprintf(stderr, "Real uid was used instead of effective uid in eaccess().\n");
:                 errorseen++;
: @@ -299,13 +299,13 @@
:         }
:
:         /* Check that the saved gid is not used */
: -       error = access("test4", R_OK);
: +       error = access("test4", /*R_OK*/ X_OK);
:         if (!error) {
:                 fprintf(stderr, "saved gid used instead of real gid\n");
:         }
:
:  #ifdef EACCESS_AVAILABLE
: -       error = eaccess("test4", R_OK);
: +       error = eaccess("test4", /*R_OK*/ X_OK);
:         if (!error) {
:                 fprintf(stderr, "saved gid used instead of effective gid\n");
:                 errorseen++;
: @@ -313,7 +313,7 @@
:  #endif
:
:         /* Check that the real gid is used, not the effective gid */
: -       error = access("test5", R_OK);
: +       error = access("test5", /*R_OK*/ X_OK);
:         if (error) {
:                 fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
:                 errorseen++;
: @@ -321,7 +321,7 @@
:
:  #ifdef EACCESS_AVAILABLE
:         /* Check that the effective gid is used, not the real gid */
: -       error = eaccess("test6", R_OK);
: +       error = eaccess("test6", /*R_OK*/ X_OK);
:         if (error) {
:                 fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
:                 errorseen++;
: @@ -329,7 +329,7 @@
:  #endif
:
:         /* Check that the real gid is used, not the effective gid */
: -       error = access("test6", R_OK);
: +       error = access("test6", /*R_OK*/ X_OK);
:         if (!error) {
:                 fprintf(stderr, "Effective gid was used instead of real gid in access().\n");
:                 errorseen++;
: @@ -337,7 +337,7 @@
:
:  #ifdef EACCESS_AVAILABLE
:         /* Check that the effective gid is used, not the real gid */
: -       error = eaccess("test5", R_OK);
: +       error = eaccess("test5", /*R_OK*/ X_OK);
:         if (!error) {
:                 fprintf(stderr, "Real gid was used instead of effective gid in eaccess().\n");
:                 errorseen++;

>Fix:

	


>Release-Note:
>Audit-Trail:

From: Jaakko Heinonen <jh@saunalahti.fi>
To: clemens fischer <ino-news@spotteswoode.dnsalias.org>,
	bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/125009: access(2) grants root execute perms for
	non-executable files
Date: Tue, 8 Jul 2008 16:29:15 +0300

 On 2008-06-26, clemens fischer wrote:
 > this check works correctly for non-root, but any file accessible in
 > any way for root _passes_ the "(access(argv[0], X_OK) < 0)" check, a
 > subsequent execvp(3) fails.  doing "git-init; date > fileA; git-commit
 > -a" as a non-privileged user works as expected.
 
 At first sight it may look like that it's not a bug. From FreeBSD
 access(2) manual page:
 
      Even if a process's real or effective user has appropriate privileges and
      indicates success for X_OK, the file may not actually have execute per-
      mission bits set.  Likewise for R_OK and W_OK.
 
 This is line with SUSv3 which states following:
 
      If any access permissions are checked, each shall be checked
      individually, as described in the Base Definitions volume of IEEE Std
      1003.1-2001, Chapter 3, Definitions. If the process has appropriate
      privileges, an implementation may indicate success for X_OK even if none
      of the execute file permission bits are set.
 
 However it boils down to how one defines "appropriate privileges".
 execve(2) has a special check for root: a file must have at least one
 execute bit set, otherwise execve(2) returns EACCES even for root.
 Thus I think that it's reasonable to say that there aren't "appropriate
 privileges" for root unless at least one execute bit is set for a
 (regular) file.
 
 This patch adds a similar execute bit check that execve(2) has to
 access(2).
 
 %%%
 Index: sys/kern/vfs_syscalls.c
 ===================================================================
 --- sys/kern/vfs_syscalls.c	(revision 180121)
 +++ sys/kern/vfs_syscalls.c	(working copy)
 @@ -2037,6 +2037,7 @@ vn_access(vp, user_flags, cred, td)
  	/* Flags == 0 means only check for existence. */
  	error = 0;
  	if (user_flags) {
 +		struct vattr vattr;
  		flags = 0;
  		if (user_flags & R_OK)
  			flags |= VREAD;
 @@ -2051,6 +2052,17 @@ vn_access(vp, user_flags, cred, td)
  #endif
  		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
  			error = VOP_ACCESS(vp, flags, cred, td);
 +		if (error)
 +			return (error);
 +		/*
 +		 * When checking execute permission insure that at least one
 +		 * execute bit is on (except for directories) - otherwise root
 +		 * will always succeed.
 +		 */
 +		if ((flags & VEXEC) &&
 +		    ((error = VOP_GETATTR(vp, &vattr, cred, td)) == 0) &&
 +		    (vattr.va_type != VDIR) && ((vattr.va_mode & 0111) == 0))
 +			error = EACCES;
  	}
  	return (error);
  }
 %%%
 
 However I think that it would be more logical to move that check down to
 vaccess() and remove the extra check from exec_check_permissions(). But
 there is a thing you have to note: vaccess() is not called when ACLs are
 used. Thus the check must be added to vaccess_acl_posix1e() too.
 Following patch should do it.
 
 %%%
 Index: sys/kern/kern_exec.c
 ===================================================================
 --- sys/kern/kern_exec.c	(revision 180335)
 +++ sys/kern/kern_exec.c	(working copy)
 @@ -1291,13 +1291,9 @@ exec_check_permissions(imgp)
  	/*
  	 * 1) Check if file execution is disabled for the filesystem that this
  	 *	file resides on.
 -	 * 2) Insure that at least one execute bit is on - otherwise root
 -	 *	will always succeed, and we don't want to happen unless the
 -	 *	file really is executable.
 -	 * 3) Insure that the file is a regular file.
 +	 * 2) Insure that the file is a regular file.
  	 */
  	if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
 -	    ((attr->va_mode & 0111) == 0) ||
  	    (attr->va_type != VREG))
  		return (EACCES);
  
 Index: sys/kern/subr_acl_posix1e.c
 ===================================================================
 --- sys/kern/subr_acl_posix1e.c	(revision 180335)
 +++ sys/kern/subr_acl_posix1e.c	(working copy)
 @@ -85,8 +85,14 @@ vaccess_acl_posix1e(enum vtype type, uid
  		     PRIV_VFS_LOOKUP, 0))
  			priv_granted |= VEXEC;
  	} else {
 +		/*
 +		 * Insure that at least one execute bit is on - otherwise
 +		 * privileged user will always succeed, and we don't want to
 +		 * happen unless the file really is executable.
 +		 */
  		if ((acc_mode & VEXEC) && !priv_check_cred(cred,
 -		    PRIV_VFS_EXEC, 0))
 +		    PRIV_VFS_EXEC, 0) && (acl_posix1e_acl_to_mode(acl) &
 +		    (S_IXUSR | S_IXGRP | S_IXOTH)))
  			priv_granted |= VEXEC;
  	}
  
 Index: sys/kern/vfs_subr.c
 ===================================================================
 --- sys/kern/vfs_subr.c	(revision 180335)
 +++ sys/kern/vfs_subr.c	(working copy)
 @@ -3517,8 +3517,14 @@ privcheck:
  		    !priv_check_cred(cred, PRIV_VFS_LOOKUP, 0))
  			priv_granted |= VEXEC;
  	} else {
 +		/*
 +		 * Insure that at least one execute bit is on - otherwise
 +		 * privileged user will always succeed, and we don't want to
 +		 * happen unless the file really is executable.
 +		 */
  		if ((acc_mode & VEXEC) && ((dac_granted & VEXEC) == 0) &&
 -		    !priv_check_cred(cred, PRIV_VFS_EXEC, 0))
 +		    !priv_check_cred(cred, PRIV_VFS_EXEC, 0) &&
 +		    (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
  			priv_granted |= VEXEC;
  	}
  
 %%%
 
 I also tested how some other operating systems behave:
 
 (access(2) X_OK call as root for a regular file which has no execute
 bits set)
 
 Mac OS X 10.4 returns EPERM (for users it returns EACCES and strangely
 it returns 0 (OK) for device files)
 
 Linux (recent Ubuntu kernel) returns EACCES
 
 NetBSD returns EACCES
 
 OpenBSD 4.3 returns 0 (same as FreeBSD)
  
 > but this isn't a git-problem anyway:  i took
 > /usr/src/tools/regression/security/access/* and changed every check for
 > "access(path, R_OK)" into "access(path, X_OK)".  as the test files in
 > this test are created modes 0400 and 0040, one would expect every check
 > to fail when using X_OK, but the output is:
 > 
 > : /src/localcode/test/access
 > : 0  # ./testaccess
 > : Effective uid was used instead of real uid in access().
 > : Effective gid was used instead of real gid in access().
 > : 2 errors seen.
 
 I don't think that your change to the test and these errors are relevant 
 to the actual problem. I didn't check thoroughly though.
 
 -- 
 Jaakko

From: clemens fischer <ino-news@spotteswoode.dnsalias.org>
To: Jaakko Heinonen <jh@saunalahti.fi>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/125009: access(2) grants root execute perms for
	non-executable files
Date: Tue, 8 Jul 2008 16:17:47 +0200

 > Jaakko Heinonen:
 
 > On 2008-06-26, clemens fischer wrote:
 
 > > this check works correctly for non-root, but any file accessible in
 > > any way for root _passes_ the "(access(argv[0], X_OK) < 0)" check,
 > > a subsequent execvp(3) fails.  doing "git-init; date > fileA;
 > > git-commit -a" as a non-privileged user works as expected.
 >
 > At first sight it may look like that it's not a bug. From FreeBSD
 > access(2) manual page:
 >
 >      Even if a process's real or effective user has appropriate
 >      privileges and indicates success for X_OK, the file may not
 >      actually have execute per- mission bits set.  Likewise for R_OK
 >      and W_OK.
 
 ok, i read this passage, and the "bug" is documented behaviour, but it
 doesn't make sense in real life. hence the way git(1) fails.  Linux
 returning EACCES follows the principle of least astinishment. it saves
 programmers writing extra code when all he wanted to express has already
 been tested.
 
 > However it boils down to how one defines "appropriate privileges".
 > execve(2) has a special check for root: a file must have at least one
 > execute bit set, otherwise execve(2) returns EACCES even for root.
 > Thus I think that it's reasonable to say that there aren't
 > "appropriate privileges" for root unless at least one execute bit is
 > set for a (regular) file.
 
 oh, yes!
 
 > [text of patches removed, they look correct to me]
 
 > I also tested how some other operating systems behave:
 >
 > (access(2) X_OK call as root for a regular file which has no execute
 > bits set)
 >
 > Mac OS X 10.4 returns EPERM (for users it returns EACCES and strangely
 > it returns 0 (OK) for device files)
 >
 > Linux (recent Ubuntu kernel) returns EACCES
 >
 > NetBSD returns EACCES
 >
 > OpenBSD 4.3 returns 0 (same as FreeBSD)
 
 i really appreciate your looking into this so thoroughly!
 
 > > but this isn't a git-problem anyway:  i took
 > > /usr/src/tools/regression/security/access/* and changed every check for
 > > "access(path, R_OK)" into "access(path, X_OK)".  as the test files in
 > > this test are created modes 0400 and 0040, one would expect every check
 > > to fail when using X_OK, but the output is:
 > >
 > > : /src/localcode/test/access
 > > : 0  # ./testaccess
 > > : Effective uid was used instead of real uid in access().
 > > : Effective gid was used instead of real gid in access().
 > > : 2 errors seen.
 >
 > I don't think that your change to the test and these errors are relevant
 > to the actual problem. I didn't check thoroughly though.
 
 well, if access(2) had made sure any execute bits were set, _all_ the
 tests had failed.
 
 i hope your fix is committed.
 
 
 regards, clemens
Responsible-Changed-From-To: freebsd-bugs->jh 
Responsible-Changed-By: jh 
Responsible-Changed-When: Wed Aug 11 14:38:51 UTC 2010 
Responsible-Changed-Why:  
I am working on this. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=125009 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/125009: commit references a PR
Date: Mon, 30 Aug 2010 16:30:29 +0000 (UTC)

 Author: jh
 Date: Mon Aug 30 16:30:18 2010
 New Revision: 212002
 URL: http://svn.freebsd.org/changeset/base/212002
 
 Log:
   execve(2) has a special check for file permissions: a file must have at
   least one execute bit set, otherwise execve(2) will return EACCES even
   for an user with PRIV_VFS_EXEC privilege.
   
   Add the check also to vaccess(9), vaccess_acl_nfs4(9) and
   vaccess_acl_posix1e(9). This makes access(2) to better agree with
   execve(2). Because ZFS doesn't use vaccess(9) for VEXEC, add the check
   to zfs_freebsd_access() too. There may be other file systems which are
   not using vaccess*() functions and need to be handled separately.
   
   PR:		kern/125009
   Reviewed by:	bde, trasz
   Approved by:	pjd (ZFS part)
 
 Modified:
   head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
   head/sys/kern/kern_exec.c
   head/sys/kern/subr_acl_nfs4.c
   head/sys/kern/subr_acl_posix1e.c
   head/sys/kern/vfs_subr.c
 
 Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c
 ==============================================================================
 --- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c	Mon Aug 30 15:06:55 2010	(r212001)
 +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c	Mon Aug 30 16:30:18 2010	(r212002)
 @@ -4247,6 +4247,9 @@ zfs_freebsd_access(ap)
  		struct thread *a_td;
  	} */ *ap;
  {
 +	vnode_t *vp = ap->a_vp;
 +	znode_t *zp = VTOZ(vp);
 +	znode_phys_t *zphys = zp->z_phys;
  	accmode_t accmode;
  	int error = 0;
  
 @@ -4263,16 +4266,20 @@ zfs_freebsd_access(ap)
  	if (error == 0) {
  		accmode = ap->a_accmode & ~(VREAD|VWRITE|VEXEC|VAPPEND);
  		if (accmode != 0) {
 -			vnode_t *vp = ap->a_vp;
 -			znode_t *zp = VTOZ(vp);
 -			znode_phys_t *zphys = zp->z_phys;
 -
  			error = vaccess(vp->v_type, zphys->zp_mode,
  			    zphys->zp_uid, zphys->zp_gid, accmode, ap->a_cred,
  			    NULL);
  		}
  	}
  
 +	/*
 +	 * For VEXEC, ensure that at least one execute bit is set for
 +	 * non-directories.
 +	 */
 +	if (error == 0 && (ap->a_accmode & VEXEC) != 0 && vp->v_type != VDIR &&
 +	    (zphys->zp_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)
 +		error = EACCES;
 +
  	return (error);
  }
  
 
 Modified: head/sys/kern/kern_exec.c
 ==============================================================================
 --- head/sys/kern/kern_exec.c	Mon Aug 30 15:06:55 2010	(r212001)
 +++ head/sys/kern/kern_exec.c	Mon Aug 30 16:30:18 2010	(r212002)
 @@ -1363,17 +1363,17 @@ exec_check_permissions(imgp)
  	if (error)
  		return (error);
  #endif
 -	
 +
  	/*
 -	 * 1) Check if file execution is disabled for the filesystem that this
 -	 *	file resides on.
 -	 * 2) Insure that at least one execute bit is on - otherwise root
 -	 *	will always succeed, and we don't want to happen unless the
 -	 *	file really is executable.
 -	 * 3) Insure that the file is a regular file.
 +	 * 1) Check if file execution is disabled for the filesystem that
 +	 *    this file resides on.
 +	 * 2) Ensure that at least one execute bit is on. Otherwise, a
 +	 *    privileged user will always succeed, and we don't want this
 +	 *    to happen unless the file really is executable.
 +	 * 3) Ensure that the file is a regular file.
  	 */
  	if ((vp->v_mount->mnt_flag & MNT_NOEXEC) ||
 -	    ((attr->va_mode & 0111) == 0) ||
 +	    (attr->va_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0 ||
  	    (attr->va_type != VREG))
  		return (EACCES);
  
 
 Modified: head/sys/kern/subr_acl_nfs4.c
 ==============================================================================
 --- head/sys/kern/subr_acl_nfs4.c	Mon Aug 30 15:06:55 2010	(r212001)
 +++ head/sys/kern/subr_acl_nfs4.c	Mon Aug 30 16:30:18 2010	(r212002)
 @@ -162,6 +162,7 @@ vaccess_acl_nfs4(enum vtype type, uid_t 
  	accmode_t priv_granted = 0;
  	int denied, explicitly_denied, access_mask, is_directory,
  	    must_be_owner = 0;
 +	mode_t file_mode;
  
  	KASSERT((accmode & ~(VEXEC | VWRITE | VREAD | VADMIN | VAPPEND |
  	    VEXPLICIT_DENY | VREAD_NAMED_ATTRS | VWRITE_NAMED_ATTRS |
 @@ -216,6 +217,17 @@ vaccess_acl_nfs4(enum vtype type, uid_t 
  			denied = EPERM;
  	}
  
 +	/*
 +	 * For VEXEC, ensure that at least one execute bit is set for
 +	 * non-directories. We have to check the mode here to stay
 +	 * consistent with execve(2). See the test in
 +	 * exec_check_permissions().
 +	 */
 +	acl_nfs4_sync_mode_from_acl(&file_mode, aclp);
 +	if (!denied && !is_directory && (accmode & VEXEC) &&
 +	    (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)
 +		denied = EACCES;
 +
  	if (!denied)
  		return (0);
  
 @@ -236,8 +248,14 @@ vaccess_acl_nfs4(enum vtype type, uid_t 
  		    PRIV_VFS_LOOKUP, 0))
  			priv_granted |= VEXEC;
  	} else {
 -		if ((accmode & VEXEC) && !priv_check_cred(cred,
 -		    PRIV_VFS_EXEC, 0))
 +		/*
 +		 * Ensure that at least one execute bit is on. Otherwise,
 +		 * a privileged user will always succeed, and we don't want
 +		 * this to happen unless the file really is executable.
 +		 */
 +		if ((accmode & VEXEC) && (file_mode &
 +		    (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 &&
 +		    !priv_check_cred(cred, PRIV_VFS_EXEC, 0))
  			priv_granted |= VEXEC;
  	}
  
 
 Modified: head/sys/kern/subr_acl_posix1e.c
 ==============================================================================
 --- head/sys/kern/subr_acl_posix1e.c	Mon Aug 30 15:06:55 2010	(r212001)
 +++ head/sys/kern/subr_acl_posix1e.c	Mon Aug 30 16:30:18 2010	(r212002)
 @@ -90,8 +90,14 @@ vaccess_acl_posix1e(enum vtype type, uid
  		     PRIV_VFS_LOOKUP, 0))
  			priv_granted |= VEXEC;
  	} else {
 -		if ((accmode & VEXEC) && !priv_check_cred(cred,
 -		    PRIV_VFS_EXEC, 0))
 +		/*
 +		 * Ensure that at least one execute bit is on. Otherwise,
 +		 * a privileged user will always succeed, and we don't want
 +		 * this to happen unless the file really is executable.
 +		 */
 +		if ((accmode & VEXEC) && (acl_posix1e_acl_to_mode(acl) &
 +		    (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 &&
 +		    !priv_check_cred(cred, PRIV_VFS_EXEC, 0))
  			priv_granted |= VEXEC;
  	}
  
 
 Modified: head/sys/kern/vfs_subr.c
 ==============================================================================
 --- head/sys/kern/vfs_subr.c	Mon Aug 30 15:06:55 2010	(r212001)
 +++ head/sys/kern/vfs_subr.c	Mon Aug 30 16:30:18 2010	(r212002)
 @@ -3619,7 +3619,13 @@ privcheck:
  		    !priv_check_cred(cred, PRIV_VFS_LOOKUP, 0))
  			priv_granted |= VEXEC;
  	} else {
 +		/*
 +		 * Ensure that at least one execute bit is on. Otherwise,
 +		 * a privileged user will always succeed, and we don't want
 +		 * this to happen unless the file really is executable.
 +		 */
  		if ((accmode & VEXEC) && ((dac_granted & VEXEC) == 0) &&
 +		    (file_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0 &&
  		    !priv_check_cred(cred, PRIV_VFS_EXEC, 0))
  			priv_granted |= VEXEC;
  	}
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->closed 
State-Changed-By: jh 
State-Changed-When: Fri Sep 10 04:58:53 UTC 2010 
State-Changed-Why:  
A change for vaccess*() functions and for ZFS has been committed to head 
(r212002). Note that file systems not using vaccess*(), access(2) may 
still return 0 for regular files without execute bits set. I am not 
planning to MFC the change. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=125009 
>Unformatted:
