From: Karel Zak Date: Wed, 31 Jan 2007 15:43:18 +0000 (+0100) Subject: namei: fix logic and infinite loop of symlinks X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d8ef4c19ab6ebe29b1deb5d5445cba6d76192a4f;p=util-linux namei: fix logic and infinite loop of symlinks Don't follow the path if a component is not directory. It doesn't make sense to support something like: $ touch a b $ namei a/b <-- where "a" is not directory The support for infinite loop of symbolic links is a strange wish only. The stack size is very limited. Try: $ ln -s x $ namei x/x [Migration note: severity="low"] Signed-off-by: Karel Zak --- diff --git a/misc-utils/namei.1 b/misc-utils/namei.1 index 348a3789..96fa8990 100644 --- a/misc-utils/namei.1 +++ b/misc-utils/namei.1 @@ -52,9 +52,5 @@ for example 'rwxr-xr-x'. Roger Southwick (rogers@amadeus.wr.tek.com) .SH BUGS To be discovered. -.SH CAVEATS -.I Namei -will follow an infinite loop of symbolic links forever. To escape, use -SIGINT (usually ^C). .SH "SEE ALSO" ls(1), stat(1) diff --git a/misc-utils/namei.c b/misc-utils/namei.c index 949d0165..b0c33e81 100644 --- a/misc-utils/namei.c +++ b/misc-utils/namei.c @@ -42,6 +42,10 @@ chdir to /, or if it encounters an unknown file type. 1999-02-22 Arkadiusz Mi¶kiewicz - added Native Language Support +2006-12-15 Karel Zak +- fixed logic; don't follow the path if a component is not directory +- fixed infinite loop of symbolic links; stack size is very limited + -------------------------------------------------------------*/ #include @@ -66,7 +70,7 @@ int xflag = 0; #endif static char *pperm(unsigned short); -static void namei(char *, int); +static void namei(char *, int, mode_t *); static void usage(void); int @@ -107,9 +111,10 @@ main(int argc, char **argv) { for(; optind < argc; optind++){ + mode_t lastmode = 0; (void)printf("f: %s\n", argv[optind]); symcount = 1; - namei(argv[optind], 0); + namei(argv[optind], 0, &lastmode); if(chdir(curdir) == -1){ (void)fprintf(stderr, @@ -131,8 +136,10 @@ usage(void) { #define NODEV (dev_t)(-1) #endif +int kzak; + static void -namei(char *file, int lev) { +namei(char *file, int lev, mode_t *lastmode) { char *cp; char buf[BUFSIZ], sym[BUFSIZ]; struct stat stb; @@ -142,11 +149,11 @@ namei(char *file, int lev) { /* * See if the file has a leading /, and if so cd to root */ - - if(*file == '/'){ + + if(file && *file == '/'){ while(*file == '/') file++; - + if(chdir("/") == -1){ (void)fprintf(stderr,_("namei: could not chdir to root!\n")); exit(1); @@ -166,7 +173,7 @@ namei(char *file, int lev) { (void)printf(" d /\n"); } - for(;;){ + for(; file && *file;){ if (strlen(file) >= BUFSIZ) { fprintf(stderr,_("namei: buf overflow\n")); @@ -198,6 +205,20 @@ namei(char *file, int lev) { for(i = 0; i < lev; i++) (void)printf(" "); + + /* + * We cannot walk on *path* if a previous element, in the path wasn't + * directory, because there could be a component with same name. Try: + * + * $ touch a b + * $ namei a/b <-- "a" is not directory so namei shouldn't + * check for "b" + */ + if (*lastmode && S_ISDIR(*lastmode)==0 && S_ISLNK(*lastmode)==0){ + (void)printf(" ? %s - %s (%d)\n", buf, strerror(ENOENT), ENOENT); + return; + } + /* * See what type of critter this file is */ @@ -207,6 +228,8 @@ namei(char *file, int lev) { return; } + *lastmode = stb.st_mode; + switch(stb.st_mode & S_IFMT){ case S_IFDIR: @@ -241,7 +264,6 @@ namei(char *file, int lev) { * Sigh, another symlink. Read its contents and * call namei() */ - bzero(sym, BUFSIZ); if(readlink(buf, sym, BUFSIZ) == -1){ (void)printf(_(" ? problems reading symlink %s - %s (%d)\n"), buf, ERR); @@ -255,11 +277,12 @@ namei(char *file, int lev) { if(symcount > 0 && symcount++ > MAXSYMLINKS){ (void)printf(_(" *** EXCEEDED UNIX LIMIT OF SYMLINKS ***\n")); - symcount = -1; } else { (void)printf("\n"); - namei(sym, lev + 1); + namei(sym, lev + 1, lastmode); } + if (symcount > MAXSYMLINKS) + return; break; case S_IFCHR: