const uid_t &uid,
app_install_type installationType);
- int labelPaths(path_req& req, bool isSharedRO);
+ int labelPaths(const Credentials &creds,
+ const path_req &req,
+ bool isSharedRO,
+ const std::vector<uid_t> &processUids);
void getPkgLabels(const std::string &pkgName, Smack::Labels &pkgsLabels);
#include <string>
#include <utility>
+#include <optional>
#include <smack-common.h>
#include <smack-exceptions.h>
#include <security-manager.h>
+#include "credentials.h"
namespace SecurityManager {
namespace SmackLabels {
app_install_path_type pathType,
const std::string &authorHash = std::string());
+/**
+ * Sets ACL and DAC permissions on a directory and its contents, recursively.
+ *
+ * @param creds[in] client's credentials
+ * @param path[in] path to a file or directory to setup
+ * @param pathType[in] type of path to setup. See description of
+ * app_install_path_type in security-manager.h for details
+ * @param processUIds[in] list of owner applications' process UIds (PUIDs)
+ * @param authorGId[in] optional group id of all apps having the same author
+ */
+void setupPath(
+ const Credentials& creds,
+ const std::string &path,
+ app_install_path_type pathType,
+ const std::vector<uid_t>& processUIds,
+ const std::optional<gid_t>& authorGId);
+
/**
* Sets Smack labels on a <ROOT_APP>/<pkg_id> non-recursively
*
*/
void setupPkgBasePath(const std::string &basePath);
+/**
+ * Sets ACL and DAC permissions on <ROOT_APP>/<pkg_id> non-recursively
+ *
+ * @param creds[in] client's credentials
+ * @param basePath[in] <ROOT_APP>/<pkg_id> path
+ * @param processUIds[in] list of owner applications' process UIds (PUIDs)
+ */
+void setupPkgBasePath(
+ const Credentials &creds,
+ const std::string &basePath,
+ const std::vector<uid_t> &processUIds);
+
/**
* Changes Smack label on path to enable private sharing
*
#include <pwd.h>
#include <sys/mman.h>
#include <sys/socket.h>
+#include <sys/stat.h>
#include <dirent.h>
#include <cstring>
#include <algorithm>
#include <sys/types.h>
#include <grp.h>
#include <optional>
+#include <sys/smack.h>
+#include <unistd.h>
+#include <stdexcept>
#include <dpl/log/log.h>
#include <dpl/errno_string.h>
-#include <sys/smack.h>
-
#include <config.h>
+#include "acl.h"
#include "check-proper-drop.h"
#include "protocols.h"
#include "privilege_db.h"
return true;
}
-int ServiceImpl::labelPaths(path_req& req, bool isSharedRO)
+int ServiceImpl::labelPaths(const Credentials &creds,
+ const path_req &req,
+ bool isSharedRO,
+ const std::vector<uid_t> &processUIds)
{
try {
-
- if (!smack_simple_check()) {
- LogWarning("Running in no-smack mode, not labeling any paths");
- if (!m_privilegeDb.PkgNameExists(req.pkgName)) {
- LogError("No such package: " << req.pkgName);
- return SECURITY_MANAGER_ERROR_INPUT_PARAM;
- }
- return SECURITY_MANAGER_SUCCESS;
+ if (!m_privilegeDb.PkgNameExists(req.pkgName)) {
+ LogError("No such package: " << req.pkgName);
+ return SECURITY_MANAGER_ERROR_INPUT_PARAM;
}
std::string authorHash;
return ret;
}
- LogWarning("Determinig if paths are legal");
+ LogWarning("Determining if paths are legal");
// check if paths are inside of legal directories
if (!pathsCheck(req.pkgPaths, pkgLegalBaseDirs))
return SECURITY_MANAGER_ERROR_NOT_PATH_OWNER;
for (const auto &pkgPath : req.pkgPaths) {
const std::string &path = pkgPath.first;
app_install_path_type pathType = static_cast<app_install_path_type>(pkgPath.second);
- SmackLabels::setupPath(req.pkgName, path, pathType, authorHash);
+ if (smack_simple_check()) {
+ SmackLabels::setupPath(req.pkgName, path, pathType, authorHash);
+ } else {
+ gid_t authorGId;
+ if (m_privilegeDb.GetAuthorGId(req.pkgName, authorGId))
+ SmackLabels::setupPath(creds, path, pathType, processUIds, authorGId);
+ else
+ SmackLabels::setupPath(creds, path, pathType, processUIds, std::nullopt);
+ }
}
LogWarning("Labeling base paths");
for (const auto &basePath : pkgLegalBaseDirs) {
if (containSubDir(basePath, req.pkgPaths)) {
- SmackLabels::setupPkgBasePath(basePath);
+ if (smack_simple_check())
+ SmackLabels::setupPkgBasePath(basePath);
+ else
+ SmackLabels::setupPkgBasePath(creds, basePath, processUIds);
}
}
} catch (const SmackException::Base &e) {
LogError("Error while generating Smack labels: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SETTING_FILE_LABEL_FAILED;
+ } catch (const Acl::Exception::Base &e) {
+ LogError("Error while setting up ACL");
+ return SECURITY_MANAGER_ERROR_SETTING_FILE_LABEL_FAILED;
+ } catch (const std::runtime_error &) {
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
} catch (const std::bad_alloc &e) {
LogError("Memory allocation failed: " << e.what());
return SECURITY_MANAGER_ERROR_MEMORY;
// [db] begin
ScopedTransaction trans(m_privilegeDb);
+ std::vector<uid_t> processUids;
for (auto &app : req.apps) {
// [db] add app
LogWarning("Adding privileges for app " << app.appName << " into security-manager's db");
// [cynara] update app policy
LogWarning("Configuring privileges for app " << app.appName << " in cynara");
appInstallCynaraPolicies(app, req, ih);
+
+ // collect process uids
+ if (!smack_simple_check() && (req.isHybrid || processUids.empty()))
+ processUids.emplace_back(getProcessUId(app, req));
}
// [db] update shared ro
// label paths
LogWarning("Configuring package paths");
- ret = labelPaths(req, isAppSharedRO);
+ ret = labelPaths(creds, req, isAppSharedRO, processUids);
if (ret != SECURITY_MANAGER_SUCCESS)
return ret;
// [db] begin
ScopedTransaction trans(m_privilegeDb);
+ std::vector<uid_t> processUids;
for (auto &app : req.apps) {
// [db] add app
LogWarning("Adding privileges for app " << app.appName << " into security-manager's db");
// [cynara] update app policy
LogWarning("Configuring privileges for app " << app.appName << " in cynara");
appInstallCynaraPolicies(app, req, ih);
+
+ // collect process uids
+ if (!smack_simple_check() && (req.isHybrid || processUids.empty()))
+ processUids.emplace_back(getProcessUId(app, req));
}
// [db] update shared ro
// label paths
LogWarning("Configuring package paths");
- ret = labelPaths(req, isAppSharedRO);
+ ret = labelPaths(creds, req, isAppSharedRO, processUids);
if (ret != SECURITY_MANAGER_SUCCESS)
return ret;
}
bool isRequestSharedRO = isSharedRO(req.pkgPaths);
+ std::vector<uid_t> processUids;
try {
if (isRequestSharedRO) {
ScopedTransaction trans(m_privilegeDb);
m_privilegeDb.SetSharedROPackage(req.pkgName);
+ if (!smack_simple_check()) {
+ // collect process uids
+ std::vector<std::string> apps;
+ m_privilegeDb.GetUserAppsFromPkg(creds.uid, req.pkgName, apps);
+ for (const auto &appName : apps) {
+ uid_t processUid;
+ if (!m_privilegeDb.GetProcessUId(req.pkgName, appName, processUid)) {
+ LogError("Failed to get process UId from the db");
+ return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+ }
+ if (!processUids.empty() && processUid == processUids.front())
+ break; // non-hybrid
+
+ processUids.emplace_back(processUid);
+ }
+ }
+
trans.commit();
}
} catch (const PrivilegeDb::Exception::IOError &e) {
return SECURITY_MANAGER_ERROR_SERVER_ERROR;
}
- return labelPaths(req, isRequestSharedRO);
+ return labelPaths(creds, req, isRequestSharedRO, processUids);
}
int ServiceImpl::shmAppName(const Credentials &creds, const std::string &shmName, const std::string &appName)
#include <crypt.h>
#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <sys/smack.h>
#include <sys/xattr.h>
#include <linux/xattr.h>
#include <dpl/log/log.h>
#include <dpl/errno_string.h>
+#include "acl.h"
#include "security-manager.h"
#include "service_impl_utils.h"
#include "smack-check.h"
class PathSetup {
public:
explicit PathSetup(bool transmute) : m_transmute(transmute) {}
- void setup(const std::string &path)
+ void setup(const std::string &path) const
{
// setting access label on everything in given directory and below
char *const path_argv[] = { const_cast<char*>(path.c_str()), NULL };
virtual ~PathSetup() = default;
protected:
- virtual void setupFile(FTSENT *ftsent) = 0;
+ virtual void setupFile(FTSENT *ftsent) const = 0;
bool m_transmute;
};
}
protected:
- void setupFile(FTSENT *ftsent) override
+ void setupFile(FTSENT *ftsent) const override
{
pathSetSmack(ftsent->fts_path, m_label, XATTR_NAME_SMACK);
if (m_transmute && S_ISDIR(ftsent->fts_statp->st_mode))
smack.setup(path);
}
+struct Dac {
+ // ACL for files and dirs. Effective permissions will be "ANDed" with ACL mask so
+ // non-executable files won't get 'x'
+ Acl acl;
+ uid_t owner;
+ gid_t group;
+};
+
+class DacSetup: public PathSetup {
+public:
+ DacSetup(Dac dac) : PathSetup(true), m_dac(std::move(dac)) {}
+
+ void setupFile(FTSENT *ftsent) const override
+ {
+ if (0 != chown(ftsent->fts_path, m_dac.owner, m_dac.group))
+ ThrowErrno(SmackException::FileError, "chown() for path: " << ftsent->fts_path);
+
+ m_dac.acl.apply(ftsent->fts_path, ACL_TYPE_ACCESS);
+
+ /*
+ * For newly created files:
+ * - let the owner come from process (be it app PUId or system_access). The creator clearly
+ * already has RWX.
+ * - force the group = system_access using DAC set-group-ID bit so even files created by
+ * app will be accessible by sys daemons. SM needs CAP_FSETID and system_access group for
+ * that.
+ * - Default ACL rules will be applied from the parent directory.
+ */
+ if (m_transmute && ftsent->fts_level == 0) {
+ // need to re-read the mode after ACL application above
+ struct stat statbuf;
+ if (0 != stat(ftsent->fts_path, &statbuf))
+ ThrowErrno(SmackException::FileError, "stat() for path: " << ftsent->fts_path);
+
+ // add set-group-ID for system_access
+ if (0 != chmod(ftsent->fts_path, S_ISGID | statbuf.st_mode))
+ ThrowErrno(SmackException::FileError, "chmod() for path: " << ftsent->fts_path);
+
+ // this works on all files/directories below
+ m_dac.acl.apply(ftsent->fts_path, ACL_TYPE_DEFAULT);
+ }
+ }
+
+private:
+ Dac m_dac;
+};
+
+void setupPath(const Credentials& creds,
+ const std::string &path,
+ app_install_path_type pathType,
+ const std::vector<uid_t> &processUIds,
+ const std::optional<gid_t> &authorGId)
+{
+ Dac dac;
+ // Make the real user (owner=5001) the owner. No app should run with this uid
+ dac.owner = creds.uid;
+ // Make system_access the group. No app should run with it.
+ dac.group = getSystemAccessGid();
+
+ acl_perm_t appPerms;
+ acl_perm_t otherPerms;
+ bool follow_symlink;
+ std::vector<Acl::EntryPtr> entries;
+
+ switch (pathType) {
+ case SECURITY_MANAGER_PATH_OWNER_RW_OTHER_RO:
+ appPerms = Acl::RWX;
+ otherPerms = Acl::R;
+ follow_symlink = true;
+ break;
+
+ case SECURITY_MANAGER_PATH_RW:
+ appPerms = Acl::RWX;
+ otherPerms = 0;
+ follow_symlink = false;
+ break;
+
+ case SECURITY_MANAGER_PATH_RO:
+ appPerms = Acl::RX;
+ otherPerms = 0;
+ follow_symlink = false;
+ break;
+
+ case SECURITY_MANAGER_PATH_PUBLIC_RO:
+ appPerms = Acl::RX;
+ otherPerms = Acl::R;
+ follow_symlink = false;
+ break;
+
+ case SECURITY_MANAGER_PATH_TRUSTED_RW:
+ if (!authorGId.has_value())
+ ThrowMsg(SmackException::InvalidParam, "You must define author to use PATH_TRUSED_RW");
+
+ appPerms = Acl::RWX;
+ otherPerms = 0;
+ follow_symlink = false;
+ entries.emplace_back(std::make_unique<Acl::GidEntry>(appPerms, *authorGId));
+ break;
+
+ default:
+ LogError("Path type not known.");
+ Throw(SmackException::InvalidPathType);
+ }
+
+ for (auto &processUId : processUIds)
+ entries.emplace_back(std::make_unique<Acl::UidEntry>(appPerms, processUId));
+
+ // RWX for the owner(5001) and system_access
+ dac.acl = Acl::Make(Acl::RWX, Acl::RWX, otherPerms, std::move(entries));
+
+ DacSetup dacSetup(std::move(dac));
+ if (follow_symlink)
+ dacSetup.setup(realPath(path));
+ dacSetup.setup(path);
+}
+
void setupPkgBasePath(const std::string &basePath)
{
pathSetSmack(basePath.c_str(), LABEL_FOR_APP_PUBLIC_RO_PATH, XATTR_NAME_SMACK);
}
+void setupPkgBasePath(const Credentials &creds,
+ const std::string &basePath,
+ const std::vector<uid_t> &processUIds)
+{
+ // apply public RO access permissions
+ if (0 != chown(basePath.c_str(), creds.uid, getSystemAccessGid()))
+ ThrowErrno(SmackException::FileError, "chown() for path: " << basePath);
+
+ std::vector<Acl::EntryPtr> entries;
+ for (auto &processUId : processUIds)
+ entries.emplace_back(std::make_unique<Acl::UidEntry>(Acl::RX, processUId));
+
+ auto acl = Acl::Make(Acl::RWX, Acl::RWX, Acl::RX, std::move(entries));
+ acl.apply(basePath, ACL_TYPE_ACCESS);
+}
+
void setupSharedPrivatePath(const std::string &pkgName, const std::string &path) {
pathSetSmack(path.c_str(), generateSharedPrivateLabel(pkgName, path), XATTR_NAME_SMACK);
}
mount
libcap
openssl3
+ libacl
)
FIND_PACKAGE(Threads REQUIRED)