sudo_dso_load: add AIX fallback path from shlib.so to shlib.a(shlib.so).
If the .so file is missing but the .a file exists, try to dlopen() the AIX .a file using the .so name as the member. We need to avoid breaking existing configurations if the type of AIX shared library changes when sudo is upgraded.
This commit is contained in:
@@ -215,6 +215,7 @@ sudo_dso_load_v1(const char *path, int mode)
|
||||
void *ret;
|
||||
# ifdef RTLD_MEMBER
|
||||
char *cp;
|
||||
size_t pathlen;
|
||||
# endif
|
||||
|
||||
/* Check prelinked symbols first. */
|
||||
@@ -236,30 +237,60 @@ sudo_dso_load_v1(const char *path, int mode)
|
||||
SET(flags, RTLD_LOCAL);
|
||||
|
||||
# ifdef RTLD_MEMBER
|
||||
/* Check for AIX path(module) syntax and add RTLD_MEMBER for a module. */
|
||||
/* Check for AIX shlib.a(member) syntax and dlopen() with RTLD_MEMBER. */
|
||||
pathlen = strlen(path);
|
||||
if (pathlen > 2 && path[pathlen - 1] == ')') {
|
||||
cp = strrchr(path, '(');
|
||||
if (cp != NULL) {
|
||||
size_t len = strlen(cp);
|
||||
if (len > 2 && cp[len - 1] == ')')
|
||||
if (cp != NULL && cp > path + 2 && cp[-2] == '.' && cp[-1] == 'a') {
|
||||
/* Only for archive files (e.g. sudoers.a). */
|
||||
SET(flags, RTLD_MEMBER);
|
||||
}
|
||||
}
|
||||
# endif /* RTLD_MEMBER */
|
||||
ret = dlopen(path, flags);
|
||||
# if defined(RTLD_MEMBER)
|
||||
/* Special fallback handling for AIX shared objects. */
|
||||
if (ret == NULL && !ISSET(flags, RTLD_MEMBER)) {
|
||||
switch (errno) {
|
||||
case ENOEXEC:
|
||||
/*
|
||||
* If we try to dlopen() an AIX .a file without an explicit member
|
||||
* it will fail with ENOEXEC. Try again using the default member.
|
||||
*/
|
||||
if (ret == NULL && !ISSET(flags, RTLD_MEMBER) && errno == ENOEXEC) {
|
||||
if (asprintf(&cp, "%s(%s)", path, SUDO_DSO_MEMBER) != -1) {
|
||||
if (pathlen > 2 && strcmp(&path[pathlen - 2], ".a") == 0) {
|
||||
int len = asprintf(&cp, "%s(%s)", path, SUDO_DSO_MEMBER);
|
||||
if (len != -1) {
|
||||
ret = dlopen(cp, flags|RTLD_MEMBER);
|
||||
free(cp);
|
||||
}
|
||||
if (ret == NULL) {
|
||||
/* Retry with the original path so we get the correct error. */
|
||||
/* Retry with the original path to get the correct error. */
|
||||
ret = dlopen(path, flags);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ENOENT:
|
||||
/*
|
||||
* If the .so file is missing but the .a file exists, try to
|
||||
* dlopen() the AIX .a file using the .so name as the member.
|
||||
* This is for compatibility with versions of sudo that use
|
||||
* SVR4-style shared libs, not AIX-style shared libs.
|
||||
*/
|
||||
if (pathlen > 3 && strcmp(&path[pathlen - 3], ".so") == 0) {
|
||||
int len = asprintf(&cp, "%.*s.a(%s)", (int)(pathlen - 3),
|
||||
path, sudo_basename(path));
|
||||
if (len != -1) {
|
||||
ret = dlopen(cp, flags|RTLD_MEMBER);
|
||||
free(cp);
|
||||
}
|
||||
if (ret == NULL) {
|
||||
/* Retry with the original path to get the correct error. */
|
||||
ret = dlopen(path, flags);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
# endif /* RTLD_MEMBER */
|
||||
/* On failure, try again with a multi-arch path where possible. */
|
||||
if (ret == NULL)
|
||||
|
@@ -81,7 +81,9 @@ sudo_stat_plugin(struct plugin_info *info, char *fullpath,
|
||||
}
|
||||
#ifdef _AIX
|
||||
if (status == -1 && errno == ENOENT) {
|
||||
/* Check for AIX path(module) syntax. */
|
||||
len = strlen(fullpath);
|
||||
if (len > 2 && fullpath[len - 1] == ')') {
|
||||
/* Check for AIX shlib.a(member) dlopen(3) syntax. */
|
||||
char *cp = strrchr(fullpath, '(');
|
||||
if (cp != NULL) {
|
||||
/* Only for archive files (e.g. sudoers.a). */
|
||||
@@ -91,6 +93,25 @@ sudo_stat_plugin(struct plugin_info *info, char *fullpath,
|
||||
*cp = '(';
|
||||
}
|
||||
}
|
||||
} else if (len > 3 && strcmp(&fullpath[len - 3], ".so") == 0) {
|
||||
/*
|
||||
* Check for AIX-style shlib.a if shlib.so does not exist for
|
||||
* compatibility with sudo versions that use SVR4-style shlibs.
|
||||
*/
|
||||
fullpath[len - 2] = 'a';
|
||||
fullpath[len - 1] = '\0';
|
||||
len--;
|
||||
status = stat(fullpath, sb);
|
||||
if (status == 0) {
|
||||
/* Use info->path as the member of the .a file. */
|
||||
int n = snprintf(fullpath + len, pathsize - len, "(%s)",
|
||||
sudo_basename(info->path));
|
||||
if (n < 0 || (size_t)n >= pathsize - len) {
|
||||
errno = ENAMETOOLONG;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* _AIX */
|
||||
if (status == -1 && errno == ENOENT) {
|
||||
|
Reference in New Issue
Block a user