Skip to content
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

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft

run_parts updates #707

wants to merge 4 commits into from

Conversation

cgzones
Copy link
Contributor

@cgzones cgzones commented Apr 17, 2023

  • 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

    • not owned be the executing user or root,
    • not owned by the executing group or root,
    • world-writable.
  • 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.

lib/run_part.c Fixed Show fixed Hide fixed
Comment on lines -16 to +22
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 */
Copy link
Collaborator

@alejandro-colomar alejandro-colomar Jul 2, 2024

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.)

Copy link
Collaborator

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. :)

https://www.man7.org/linux/man-pages/man3/fexecve.3.html

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.
Comment on lines +37 to +39
#ifdef HAVE_EXECVEAT
execveat (script_fd, "", args, environ, AT_EMPTY_PATH);
#else
Copy link
Collaborator

@alejandro-colomar alejandro-colomar Sep 5, 2024

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.

Copy link
Contributor Author

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?

Copy link
Collaborator

@alejandro-colomar alejandro-colomar Sep 7, 2024

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.

Copy link
Collaborator

@alejandro-colomar alejandro-colomar Sep 7, 2024

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");
Copy link
Collaborator

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)) {
Copy link
Collaborator

@alejandro-colomar alejandro-colomar Sep 6, 2024

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
Comment on lines 83 to 87
if (!S_ISREG (sb.st_mode)) {
free(s);
free (namelist[n]);
continue;
}
Copy link
Collaborator

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
Comment on lines 109 to 112
}

free(s);
free (namelist[n]);
Copy link
Collaborator

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?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants