Messages in this thread | | | Date | Sun, 4 Apr 1999 12:33:22 +0300 (EEST) | From | "J. Anastasov" <> | Subject | BUG? in sys_access() in Linux 2.2.x when euid!=0 and ruid==0 |
| |
Hi,
Is this a minor bug or feature ?
access(fnm,mask) returns EACCES when euid!=0 and ruid==0 if mask contains R_OK, W_OK or X_OK.
Why fs/open.c:sys_access() denies access for root in kernels 2.2.x ? I use attached test program. My patch is:
fs/open.c:sys_access.c():
if (current->uid) cap_clear(current->cap_effective);
must be changed to:
if (current->uid) cap_clear(current->cap_effective); else current->cap_effective = current->cap_permitted;
/* Symptom: */ /* in Linux-2.2.1 - 5 access() fails with EACCES for user root */ /* when EUID!=0 and RUID==0. current->cap_effective */ /* is 0 and must be loaded with current->cap_permitted */ /* before permission checks */ /* */ /* Patch for Linux 2.2.x: */ /* */ /* fs/open.c, sys_access(): */ /* */ /* if (current->uid) */ /* cap_clear(current->cap_effective); */ /* */ /* must be changed to (TESTED): */ /* */ /* if (current->uid) */ /* cap_clear(current->cap_effective); */ /* else */ /* current->cap_effective = current->cap_permitted; */ /* */ /* Tests: */ /* 2.0.35 OK */ /* 2.0.36 OK */ /* 2.1.* Not tested, may be when cap_* are added in the kernel */ /* 2.2.1 FAILED(BUG?) */ /* 2.2.2 FAILED(BUG?) */ /* 2.2.3 FAILED(BUG?) */ /* 2.2.4 FAILED(BUG?) */ /* 2.2.5 FAILED(BUG?) */ /* Other unices OK */ /************************************************************************/
/* Next is the test program */ /* test_access.c, J. Anastasov */ /* Test if access() returns EACCES for root in seteuid program, i.e. */ /* when euid != 0 and ruid == 0 */ /* */ /* Usage: */ /* gcc -o test_access test_access.c */ /* ./test_access */
#include <stdio.h> #include <errno.h> #include <unistd.h> #include <string.h>
/* Usage: test_access file */
/* USER_ID: any UID!=0 */ #define USER_ID 99 /* INVALID_GID: root must not be member of group with GID=INVALID_GID */ #define INVALID_GID 4321
int test(char *fnm,int mask) { int rc;
rc = access(fnm,mask); if (rc < 0) { if (EACCES == errno) { printf("access(%s,%d): %s, THIS IS A BUG\n",fnm,mask,strerror(errno)); } else { perror("access()"); } } else { printf("access(%s,%d): OK\n",fnm,mask); } return rc; } int main(int argc,char *argv[]) { int rc; FILE *fp; char tmp[80]; char *fnm;
if (getuid() || geteuid()) { printf("This program must be started as root\n"); return 1; } if (argc > 1) { fnm = argv[1]; } else { fnm = argv[0]; } /* Set ownership: UID!=0 and GID!=0 */ rc = chown(fnm,USER_ID,INVALID_GID); if (rc < 0) { perror("chown()"); return 1; } /* Grant access for USER_ID:INVALID_GID, none for others */ rc = chmod(fnm,0550); if (rc < 0) { perror("chmod()"); return 1; } /* Change EUID only */ rc = seteuid(USER_ID); if (rc < 0) { perror("seteuid()"); return 1; } printf("EUID=%d, RUID=%d\n",(int)geteuid(),(int)getuid()); #ifdef __linux__ /* grep for "Cap" in /proc/self/status */ fp = fopen("/proc/self/status","r"); if (fp) { while (fgets(tmp,sizeof(tmp)-1,fp)) { if (!strncasecmp(tmp,"Cap",3)) { printf("%s",tmp); } } fclose(fp); } #endif /* Here EUID=USER_ID, RUID=0 */ /* cap_effective is cleared and */ /* cap_permitted are not changed (RUID=0) by */ /* seteuid(USER_ID) */ /* Now check with access() while RUID=0 */ /* We expect full access for root */ rc = 0; rc += test(fnm,F_OK); rc += test(fnm,R_OK); rc += test(fnm,W_OK); rc += test(fnm,X_OK); if (!rc) { printf("OK\n"); } return 0; }
| |