Use multilib rules to look for a 64-bit group plugin on failure.
If sudo_dso_load() fails on a 64-bit system, try to load a 64-bit native version of the file using system-dependent multilib rules. If we don't support multilib on the platform, check for a version of the file that ends in "64" before the .so suffix.
This commit is contained in:
@@ -25,7 +25,7 @@
|
|||||||
.nr BA @BAMAN@
|
.nr BA @BAMAN@
|
||||||
.nr LC @LCMAN@
|
.nr LC @LCMAN@
|
||||||
.nr PS @PSMAN@
|
.nr PS @PSMAN@
|
||||||
.TH "SUDOERS" "@mansectform@" "July 29, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
.TH "SUDOERS" "@mansectform@" "August 11, 2022" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
|
||||||
.nh
|
.nh
|
||||||
.if n .ad l
|
.if n .ad l
|
||||||
.SH "NAME"
|
.SH "NAME"
|
||||||
@@ -3410,7 +3410,7 @@ has completed but before the new command has had a chance to run.
|
|||||||
In the case of a path name or argument mismatch, the command will be sent a
|
In the case of a path name or argument mismatch, the command will be sent a
|
||||||
\fRSIGKILL\fR
|
\fRSIGKILL\fR
|
||||||
signal and terminated.
|
signal and terminated.
|
||||||
This can help prevent a time of check vs. time of use issue with
|
This can help prevent a time of check versus time of use issue with
|
||||||
intercept mode where the
|
intercept mode where the
|
||||||
execve(2)
|
execve(2)
|
||||||
arguments could be altered after the
|
arguments could be altered after the
|
||||||
@@ -4979,6 +4979,34 @@ These arguments (if any) will be passed to the plugin's initialization function.
|
|||||||
If arguments are present, the string must be enclosed in double quotes
|
If arguments are present, the string must be enclosed in double quotes
|
||||||
(\&"").
|
(\&"").
|
||||||
.sp
|
.sp
|
||||||
|
On 64-bit systems, if the plugin is present but cannot be loaded,
|
||||||
|
\fBsudoers\fR
|
||||||
|
will look for a 64-bit version and, if it exists, load that as a fallback.
|
||||||
|
The exact rules for this vary by system.
|
||||||
|
On Solaris, if the plugin is stored in a directory ending in
|
||||||
|
\(lqlib\(rq,
|
||||||
|
\fBsudoers\fR
|
||||||
|
will create a fallback path by appending
|
||||||
|
\(lq/64\(rq
|
||||||
|
to the directory name;
|
||||||
|
\fI/usr/lib/sudo_plugin.so\fR
|
||||||
|
becomes
|
||||||
|
\fI/usr/lib/64/sudo_plugin.so\fR.
|
||||||
|
On Linux, a directory ending in
|
||||||
|
\(lqlib\(rq
|
||||||
|
will be transformed to
|
||||||
|
\(lqlib64\(rq
|
||||||
|
as the fallback path;
|
||||||
|
\fI/usr/lib/sudo_plugin.so\fR
|
||||||
|
becomes
|
||||||
|
\fI/usr/lib64/sudo_plugin.so\fR.
|
||||||
|
On all other systems, the fallback path is generated by adding a
|
||||||
|
\(lq64\(rq
|
||||||
|
before the file extension;
|
||||||
|
\fIsudo_plugin.so\fR
|
||||||
|
becomes
|
||||||
|
\fIsudo_plugin64.so\fR.
|
||||||
|
.sp
|
||||||
For more information see
|
For more information see
|
||||||
\fIGROUP PROVIDER PLUGINS\fR.
|
\fIGROUP PROVIDER PLUGINS\fR.
|
||||||
.TP 14n
|
.TP 14n
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
.nr BA @BAMAN@
|
.nr BA @BAMAN@
|
||||||
.nr LC @LCMAN@
|
.nr LC @LCMAN@
|
||||||
.nr PS @PSMAN@
|
.nr PS @PSMAN@
|
||||||
.Dd July 29, 2022
|
.Dd August 11, 2022
|
||||||
.Dt SUDOERS @mansectform@
|
.Dt SUDOERS @mansectform@
|
||||||
.Os Sudo @PACKAGE_VERSION@
|
.Os Sudo @PACKAGE_VERSION@
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@@ -3231,7 +3231,7 @@ has completed but before the new command has had a chance to run.
|
|||||||
In the case of a path name or argument mismatch, the command will be sent a
|
In the case of a path name or argument mismatch, the command will be sent a
|
||||||
.Dv SIGKILL
|
.Dv SIGKILL
|
||||||
signal and terminated.
|
signal and terminated.
|
||||||
This can help prevent a time of check vs. time of use issue with
|
This can help prevent a time of check versus time of use issue with
|
||||||
intercept mode where the
|
intercept mode where the
|
||||||
.Xr execve 2
|
.Xr execve 2
|
||||||
arguments could be altered after the
|
arguments could be altered after the
|
||||||
@@ -4690,6 +4690,34 @@ These arguments (if any) will be passed to the plugin's initialization function.
|
|||||||
If arguments are present, the string must be enclosed in double quotes
|
If arguments are present, the string must be enclosed in double quotes
|
||||||
.Pq \&"" .
|
.Pq \&"" .
|
||||||
.Pp
|
.Pp
|
||||||
|
On 64-bit systems, if the plugin is present but cannot be loaded,
|
||||||
|
.Nm
|
||||||
|
will look for a 64-bit version and, if it exists, load that as a fallback.
|
||||||
|
The exact rules for this vary by system.
|
||||||
|
On Solaris, if the plugin is stored in a directory ending in
|
||||||
|
.Dq lib ,
|
||||||
|
.Nm
|
||||||
|
will create a fallback path by appending
|
||||||
|
.Dq /64
|
||||||
|
to the directory name;
|
||||||
|
.Pa /usr/lib/sudo_plugin.so
|
||||||
|
becomes
|
||||||
|
.Pa /usr/lib/64/sudo_plugin.so .
|
||||||
|
On Linux, a directory ending in
|
||||||
|
.Dq lib
|
||||||
|
will be transformed to
|
||||||
|
.Dq lib64
|
||||||
|
as the fallback path;
|
||||||
|
.Pa /usr/lib/sudo_plugin.so
|
||||||
|
becomes
|
||||||
|
.Pa /usr/lib64/sudo_plugin.so .
|
||||||
|
On all other systems, the fallback path is generated by adding a
|
||||||
|
.Dq 64
|
||||||
|
before the file extension;
|
||||||
|
.Pa sudo_plugin.so
|
||||||
|
becomes
|
||||||
|
.Pa sudo_plugin64.so .
|
||||||
|
.Pp
|
||||||
For more information see
|
For more information see
|
||||||
.Sx "GROUP PROVIDER PLUGINS" .
|
.Sx "GROUP PROVIDER PLUGINS" .
|
||||||
.It lecture
|
.It lecture
|
||||||
|
@@ -40,6 +40,90 @@ static void *group_handle;
|
|||||||
static struct sudoers_group_plugin *group_plugin;
|
static struct sudoers_group_plugin *group_plugin;
|
||||||
const char *path_plugin_dir = _PATH_SUDO_PLUGIN_DIR;
|
const char *path_plugin_dir = _PATH_SUDO_PLUGIN_DIR;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for a fallback path when the original group plugin is not loadable.
|
||||||
|
* Returns true on success, rewriting path and filling in sb, else false.
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
group_plugin_fallback(char *path, size_t pathsize, struct stat *sb)
|
||||||
|
{
|
||||||
|
#if defined(__LP64__)
|
||||||
|
char newpath[PATH_MAX];
|
||||||
|
bool ret = false;
|
||||||
|
int len;
|
||||||
|
debug_decl(group_plugin_fallback, SUDOERS_DEBUG_UTIL);
|
||||||
|
|
||||||
|
# if defined(__sun__) || defined(__linux__)
|
||||||
|
/*
|
||||||
|
* Solaris uses /lib/64 and /usr/lib/64 for 64-bit libraries.
|
||||||
|
* Linux may use /lib64 and /usr/lib64 for 64-bit libraries.
|
||||||
|
* If dirname(path) ends in /lib, try /lib/64 (Solaris) or /lib64 (Linux).
|
||||||
|
*/
|
||||||
|
# if defined(__sun__)
|
||||||
|
const char *lib64 = "lib/64";
|
||||||
|
# else
|
||||||
|
const char *lib64 = "lib64";
|
||||||
|
# endif
|
||||||
|
const char *base, *slash;
|
||||||
|
int dirlen;
|
||||||
|
|
||||||
|
slash = strrchr(path, '/');
|
||||||
|
if (slash == NULL) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
base = slash + 1;
|
||||||
|
|
||||||
|
/* Collapse consecutive slashes. */
|
||||||
|
while (slash > path && slash[-1] == '/') {
|
||||||
|
slash--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If directory ends in /lib/, try again with /lib/64/ or /lib64/. */
|
||||||
|
dirlen = slash - path;
|
||||||
|
if (dirlen < 4 || strncmp(slash - 4, "/lib", 4) != 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
dirlen -= 4;
|
||||||
|
len = snprintf(newpath, sizeof(newpath), "%.*s/%s/%s", dirlen, path, lib64,
|
||||||
|
base);
|
||||||
|
# else /* !__sun__ && !__linux__ */
|
||||||
|
/*
|
||||||
|
* Multilib not supported, check for a path of the form libfoo64.so.
|
||||||
|
*/
|
||||||
|
const char *dot;
|
||||||
|
int plen;
|
||||||
|
|
||||||
|
dot = strrchr(path, '.');
|
||||||
|
if (dot == NULL) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
plen = dot - path;
|
||||||
|
|
||||||
|
/* If basename(path) doesn't match libfoo64.so, try adding the 64. */
|
||||||
|
if (plen >= 2 && strncmp(dot - 2, "64", 2) == 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
len = snprintf(newpath, sizeof(newpath), "%.*s64%s", plen, path, dot);
|
||||||
|
# endif /* __sun__ || __linux__ */
|
||||||
|
if (len < 0 || len >= ssizeof(newpath)) {
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (stat(newpath, sb) == -1) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (strlcpy(path, newpath, pathsize) >= pathsize) {
|
||||||
|
errno = ENAMETOOLONG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
ret = true;
|
||||||
|
done:
|
||||||
|
debug_return_bool(ret);
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif /* __LP64__ */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load the specified plugin and run its init function.
|
* Load the specified plugin and run its init function.
|
||||||
* Returns -1 if unable to open the plugin, else it returns
|
* Returns -1 if unable to open the plugin, else it returns
|
||||||
@@ -52,6 +136,7 @@ group_plugin_load(const char *plugin_info)
|
|||||||
char *args, path[PATH_MAX];
|
char *args, path[PATH_MAX];
|
||||||
char **argv = NULL;
|
char **argv = NULL;
|
||||||
int len, rc = -1;
|
int len, rc = -1;
|
||||||
|
bool retry = true;
|
||||||
debug_decl(group_plugin_load, SUDOERS_DEBUG_UTIL);
|
debug_decl(group_plugin_load, SUDOERS_DEBUG_UTIL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -72,31 +157,41 @@ group_plugin_load(const char *plugin_info)
|
|||||||
(*plugin_info != '/') ? path_plugin_dir : "", plugin_info);
|
(*plugin_info != '/') ? path_plugin_dir : "", plugin_info);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check owner and mode of plugin path. */
|
|
||||||
if (stat(path, &sb) != 0) {
|
if (stat(path, &sb) != 0) {
|
||||||
sudo_warn("%s", path);
|
sudo_warn("%s", path);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
if (!sudo_conf_developer_mode()) {
|
|
||||||
if (sb.st_uid != ROOT_UID) {
|
for (;;) {
|
||||||
sudo_warnx(U_("%s must be owned by uid %d"), path, ROOT_UID);
|
if (!sudo_conf_developer_mode()) {
|
||||||
goto done;
|
/* Check owner and mode of plugin path. */
|
||||||
}
|
if (sb.st_uid != ROOT_UID) {
|
||||||
if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
|
sudo_warnx(U_("%s must be owned by uid %d"), path, ROOT_UID);
|
||||||
sudo_warnx(U_("%s must only be writable by owner"), path);
|
goto done;
|
||||||
goto done;
|
}
|
||||||
}
|
if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0) {
|
||||||
|
sudo_warnx(U_("%s must only be writable by owner"), path);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
group_handle = sudo_dso_load(path, SUDO_DSO_LAZY|SUDO_DSO_GLOBAL);
|
||||||
|
if (group_handle != NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!retry || !group_plugin_fallback(path, sizeof(path), &sb)) {
|
||||||
|
const char *errstr = sudo_dso_strerror();
|
||||||
|
sudo_warnx(U_("unable to load %s: %s"), path,
|
||||||
|
errstr ? errstr : "unknown error");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Retry once with the fallback path. */
|
||||||
|
retry = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open plugin and map in symbol. */
|
/* Map in symbol from group plugin. */
|
||||||
group_handle = sudo_dso_load(path, SUDO_DSO_LAZY|SUDO_DSO_GLOBAL);
|
|
||||||
if (!group_handle) {
|
|
||||||
const char *errstr = sudo_dso_strerror();
|
|
||||||
sudo_warnx(U_("unable to load %s: %s"), path,
|
|
||||||
errstr ? errstr : "unknown error");
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
group_plugin = sudo_dso_findsym(group_handle, "group_plugin");
|
group_plugin = sudo_dso_findsym(group_handle, "group_plugin");
|
||||||
if (group_plugin == NULL) {
|
if (group_plugin == NULL) {
|
||||||
sudo_warnx(U_("unable to find symbol \"group_plugin\" in %s"), path);
|
sudo_warnx(U_("unable to find symbol \"group_plugin\" in %s"), path);
|
||||||
|
Reference in New Issue
Block a user