#include "service_impl_utils.h"
+#include <fcntl.h>
+#include <limits.h>
+
#include <functional>
#include <dpl/log/log.h>
std::string realPath(const std::string &path)
{
- auto real_pathPtr = makeUnique(realpath(path.c_str(), nullptr), free);
- if (!real_pathPtr) {
- WarnErrno("realpath(" << path << ')');
+ /*
+ * The realpath() function does not honor CAP_DAC_OVERRIDE nor CAP_DAC_READ_SEARCH when
+ * traversing the directory tree. As a result a process having these capabilities not running as
+ * root may get EACCES when calling realpath(). This an undocumented/implementation specific
+ * "feature" of realpath. The problem occurred after dropping root (while keeping caps) in
+ * security-manager.
+ *
+ * To work around it a following approach has been applied:
+ * 1. Open the file descriptor to the path in question.
+ * 2. Once it's opened, a proper symlink should appear in /proc/<pid>/fd pointing to the
+ * absolute canonicalized path.
+ * 3. Read the symlink target with readlink() to get that path.
+ */
+ auto fd = open(path.c_str(), O_PATH | O_RDONLY);
+ if (fd == -1) {
+ WarnErrno("open(" << path << ')');
return std::string();
}
- return real_pathPtr.get();
+ auto fdPtr = makeUnique(&fd, [](decltype(fd) *toClose) {
+ if (toClose != nullptr)
+ close(*toClose);
+ });
+
+ auto fdPath = std::string("/proc/self/fd/" + std::to_string(fd));
+ std::string buf(127, '\0');
+ ssize_t ret = 0;
+ for(;;) {
+ ret = readlink(fdPath.c_str(), buf.data(), buf.size());
+ if (ret < 0) {
+ WarnErrno("readlink(" << path << ')');
+ return std::string();
+ }
+ if (static_cast<size_t>(ret) < buf.size())
+ break;
+
+ buf.resize(buf.size() * 2 + 1);
+ }
+ buf.resize(ret);
+ return buf;
}
int getLegalPkgBaseDirs(const uid_t &uid,
if (!caps)
LogAndThrowErrno(SecurityManager::Exception, "Error in cap_get_proc");
- // Set the system_share group to get +x in app directories
- gid_t group = getGidByName("system_share");
- if (setgroups(1, &group))
- LogAndThrowErrno(SecurityManager::Exception, "Failed to set supplementary group " << group);
-
// Change uid to non-root
uid_t uid = getUidByName("security_fw");
if (-1 == setuid(uid))