-
Notifications
You must be signed in to change notification settings - Fork 229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
run_parts updates #707
base: master
Are you sure you want to change the base?
run_parts updates #707
Conversation
int run_part (char *script_path, const char *name, const char *action) | ||
#ifdef HAVE_EXECVEAT | ||
int run_part (int script_fd, const char *script_name, const char *name, const char *action) | ||
#else | ||
int run_part (const char *script_path, const char *script_name, const char *name, const char *action) | ||
#endif /* HAVE_EXECVEAT */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about using /proc/self/fd/n
? That wouldn't need execveat(2), so would be more portable (no need for ifdefing anything, I guess).
(I'm assuming execve(2) would work with /proc/self/fd/n
, which I didn't try.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Heh, I was implementing my own fexecve() that did that, and after doing it, I searched out of curiosity if anyone had implemented a fexecve(), and found that there exists a libc function with that name, and it's in POSIX.1-2008. :)
Similar to execution failure message.
Since stat(2) is used the result can never be a symbolic link.
Skip scripts that are either - not owned be the executing user or root, - not owned by the executing group or root, - world-writable.
Pin the script to execute before gathering its information to avoid any potential time-of-check-time-of-use issues.
#ifdef HAVE_EXECVEAT | ||
execveat (script_fd, "", args, environ, AT_EMPTY_PATH); | ||
#else |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fexecve(3) is guaranteed by POSIX.1-2008, and is equivalent to execveat(, "", , AT_EMPTY_PATH)
. I suggest using fexecve(3), which can be used unconditionally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example OpenBSD does neither support execveat(2)
nor fexecve(3)
, is unconditional usage fine?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fexecve(3) can be trivially implemented as a wrapper around execve(2). If someone needs to port shadow somewhere where there's no fexecve(3), we could add our own implementation.
int
fexecve(int fd, char *const argv[], char *const envp[])
{
char path[PATH_MAX];
if (SNPRINTF(path, "/proc/self/fd/%d", fd) == -1)
return -1;
return execve(path, argv, envp);
}
(I wrote it quickly for this reply; I may have forgotten some details, and it might be buggy.)
This implementation of course needs that the OS has a proc(5) file system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I would not add that fallback implementation until someone actually tries to port shadow to such a system.
For now, I think it's better to make it unconditionally use libc's fexecve(3).
lib/run_part.c
Outdated
fprintf(stderr, "could not allocate memory\n"); | ||
fprintf(shadow_logfd, "could not allocate memory\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a lot of perror(3) calls in nearby code. Why use shadow_logfd
here and stderr (implied by perror(3)) elsewhere? I see there 's one fprintf() below, but perror(3) seems to be the most common one.
I would maybe replace this by perror("asprintf");
@@ -80,7 +80,7 @@ int run_parts (const char *directory, const char *name, const char *action) | |||
return (1); | |||
} | |||
|
|||
if (S_ISREG (sb.st_mode) || S_ISLNK (sb.st_mode)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. At least I couldn't make it evaluate to true with some tests. Even a broken link or a link pointing to itself won't trigger this, because stat(2) will just fail.
For patch 2:
Reviewed-by: Alejandro Colomar <[email protected]>
lib/run_part.c
Outdated
if (!S_ISREG (sb.st_mode)) { | ||
free(s); | ||
free (namelist[n]); | ||
continue; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd prefer a goto, to centralize the free(3) calls.
lib/run_part.c
Outdated
} | ||
|
||
free(s); | ||
free (namelist[n]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about a label here for jumping?
use shadow_logfd instead of stdout
Similar to execution failure message.
run_part: drop void symlink check
Since stat(2) is used the result can never be a symbolic link.
skip scripts with insecure ownership/permission
Skip scripts that are either
use execveat(2) to avoid toctou issues
Pin the script to execute before gathering its information to avoid any potential time-of-check-time-of-use issues.