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:
@@ -124,7 +124,7 @@ sudo_dso_findsym_v1(void *vhandle, const char *symbol)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note that the behavior of of SUDO_DSO_NEXT and SUDO_DSO_SELF
|
* Note that the behavior of of SUDO_DSO_NEXT and SUDO_DSO_SELF
|
||||||
* differs from most implementations when called from
|
* differs from most implementations when called from
|
||||||
* a shared library.
|
* a shared library.
|
||||||
*/
|
*/
|
||||||
@@ -176,7 +176,7 @@ sudo_dso_strerror_v1(void)
|
|||||||
# endif
|
# endif
|
||||||
|
|
||||||
# if defined(__linux__)
|
# if defined(__linux__)
|
||||||
/*
|
/*
|
||||||
* On Linux systems that use multi-arch, the actual DSO may be
|
* On Linux systems that use multi-arch, the actual DSO may be
|
||||||
* in a machine-specific subdirectory. If the specified path
|
* in a machine-specific subdirectory. If the specified path
|
||||||
* contains /lib/ or /libexec/, insert a multi-arch directory
|
* contains /lib/ or /libexec/, insert a multi-arch directory
|
||||||
@@ -215,6 +215,7 @@ sudo_dso_load_v1(const char *path, int mode)
|
|||||||
void *ret;
|
void *ret;
|
||||||
# ifdef RTLD_MEMBER
|
# ifdef RTLD_MEMBER
|
||||||
char *cp;
|
char *cp;
|
||||||
|
size_t pathlen;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
/* Check prelinked symbols first. */
|
/* Check prelinked symbols first. */
|
||||||
@@ -236,28 +237,58 @@ sudo_dso_load_v1(const char *path, int mode)
|
|||||||
SET(flags, RTLD_LOCAL);
|
SET(flags, RTLD_LOCAL);
|
||||||
|
|
||||||
# ifdef RTLD_MEMBER
|
# 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. */
|
||||||
cp = strrchr(path, '(');
|
pathlen = strlen(path);
|
||||||
if (cp != NULL) {
|
if (pathlen > 2 && path[pathlen - 1] == ')') {
|
||||||
size_t len = strlen(cp);
|
cp = strrchr(path, '(');
|
||||||
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);
|
SET(flags, RTLD_MEMBER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
# endif /* RTLD_MEMBER */
|
# endif /* RTLD_MEMBER */
|
||||||
ret = dlopen(path, flags);
|
ret = dlopen(path, flags);
|
||||||
# if defined(RTLD_MEMBER)
|
# if defined(RTLD_MEMBER)
|
||||||
/*
|
/* Special fallback handling for AIX shared objects. */
|
||||||
* If we try to dlopen() an AIX .a file without an explicit member
|
if (ret == NULL && !ISSET(flags, RTLD_MEMBER)) {
|
||||||
* it will fail with ENOEXEC. Try again using the default member.
|
switch (errno) {
|
||||||
*/
|
case ENOEXEC:
|
||||||
if (ret == NULL && !ISSET(flags, RTLD_MEMBER) && errno == ENOEXEC) {
|
/*
|
||||||
if (asprintf(&cp, "%s(%s)", path, SUDO_DSO_MEMBER) != -1) {
|
* If we try to dlopen() an AIX .a file without an explicit member
|
||||||
ret = dlopen(cp, flags|RTLD_MEMBER);
|
* it will fail with ENOEXEC. Try again using the default member.
|
||||||
free(cp);
|
*/
|
||||||
}
|
if (pathlen > 2 && strcmp(&path[pathlen - 2], ".a") == 0) {
|
||||||
if (ret == NULL) {
|
int len = asprintf(&cp, "%s(%s)", path, SUDO_DSO_MEMBER);
|
||||||
/* Retry with the original path so we get the correct error. */
|
if (len != -1) {
|
||||||
ret = dlopen(path, flags);
|
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;
|
||||||
|
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 */
|
# endif /* RTLD_MEMBER */
|
||||||
|
@@ -81,14 +81,35 @@ sudo_stat_plugin(struct plugin_info *info, char *fullpath,
|
|||||||
}
|
}
|
||||||
#ifdef _AIX
|
#ifdef _AIX
|
||||||
if (status == -1 && errno == ENOENT) {
|
if (status == -1 && errno == ENOENT) {
|
||||||
/* Check for AIX path(module) syntax. */
|
len = strlen(fullpath);
|
||||||
char *cp = strrchr(fullpath, '(');
|
if (len > 2 && fullpath[len - 1] == ')') {
|
||||||
if (cp != NULL) {
|
/* Check for AIX shlib.a(member) dlopen(3) syntax. */
|
||||||
/* Only for archive files (e.g. sudoers.a). */
|
char *cp = strrchr(fullpath, '(');
|
||||||
if (cp > fullpath + 2 && cp[-2] == '.' && cp[-1] == 'a') {
|
if (cp != NULL) {
|
||||||
*cp = '\0';
|
/* Only for archive files (e.g. sudoers.a). */
|
||||||
status = stat(fullpath, sb);
|
if (cp > fullpath + 2 && cp[-2] == '.' && cp[-1] == 'a') {
|
||||||
*cp = '(';
|
*cp = '\0';
|
||||||
|
status = stat(fullpath, sb);
|
||||||
|
*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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user