Re: [PATCH 1/2] run-command: Add checks after execvp fails with EACCES
From: Frans Klaver <hidden>
Date: 2016-06-15 22:52:34
Thanks for the review. There's a lot of things you mention that I either didn't see (staring blind, you know) or that I didn't know of. On Tue, Dec 6, 2011 at 11:35 PM, Junio C Hamano [off-list ref] wrote:
Frans Klaver [off-list ref] writes:quoted
+#ifndef WIN32 +static int is_in_group(gid_t gid) ... +static int have_read_execute_permissions(const char *path) +{ + struct stat s; + trace_printf("checking '%s'\n", path); + + if (stat(path, &s) < 0) { + ... + /* check world permissions */ + if ((s.st_mode&(S_IXOTH|S_IROTH)) == (S_IXOTH|S_IROTH)) + return 1;Hmm, do you need to do this with stat(2)? Wouldn't access(2) with R_OK|X_OK give you exactly what you want without this much trouble?
Probably. I'll use access instead in a reroll.
I also think that your permission check is incorrectly implemented. $ cd /var/tmp && date >j && chmod 044 j && ls -l j ----r--r-- 1 junio junio 29 Dec 6 14:32 j $ cat j cat: j: Permission denied $ su pogo Password: $ cat j Tue Dec 6 14:32:23 PST 2011 That's a world-readable but unreadable-only-to-me file.
Hmm, this is a case that didn't fit my expectations. Thanks for catching.
quoted
+static void diagnose_execvp_eacces(const char *cmd, const char **argv) +{ + /* man 2 execve states that EACCES is returned for:/* * Just a style, but we tend to write multi-line comment like * this, without anything else on opening and closing lines of * the comment block. */quoted
+ * - The file system is mounted noexec + */ + struct strbuf sb = STRBUF_INIT; + char *path = getenv("PATH"); + char *next; + + if (strchr(cmd, '/')) { + if (!have_read_execute_permissions(cmd)) + error("no read/execute permissions on '%s'\n", cmd); + return; + }Ok, execvp() failed and "cmd" has at least one slash, so we know we did not look for it in $PATH. We check only one and return (did you need getenv() in that case?).
Obviously not. Missed that.
quoted
+ for (;;) { + next = strchrnul(path, ':'); + if (path < next) + strbuf_add(&sb, path, next - path); + else + strbuf_addch(&sb, '.');Nice touch that you did not forget an empty component on $PATH.
Yes, that's a relic from me starting work based on one of your proposed patches[1]. So that one goes to you. [1] http://article.gmane.org/gmane.comp.version-control.git/171838
quoted
+ if (!have_read_execute_permissions(sb.buf)) + error("no read/execute permissions on '%s'\n", sb.buf);Don't you want to continue here upon error, after resetting sb? You just saw the directory is unreadble, so you know next file_exists() will fail before you try it.
Yes. I thought about that. I didn't do that because of the fact that I
had to do more than just resetting sb. The path variable has to be
updated as well. I had the choice of adding a level of indentation {},
duplicating the code, or just do a check I know before will fail.
There's probably something to say for each one of them. I'll probably
refactor that a bit more.
quoted
+ if (sb.len && sb.buf[sb.len - 1] != '/') + strbuf_addch(&sb, '/'); + strbuf_addstr(&sb, cmd); + + if (file_exists(sb.buf)) { + if (!have_read_execute_permissions(sb.buf)) + error("no read/execute permissions on '%s'\n", + sb.buf); + else + warn("file '%s' exists and permissions " + "seem OK.\nIf this is a script, see if you " + "have sufficient privileges to run the " + "interpreter", sb.buf);Does "warn()" do the right thing for multi-line strings like this?
I don't know/remember. It seemed like a natural thing to do, but I'll find out.