#include <sys/stat.h>
#include <sys/types.h>
+#include <client-request.h>
#include <config.h>
#include <dpl/log/log.h>
#include <dpl/errno_string.h>
#include <permissible-set.h>
#include <protocols.h>
#include <smack-labels.h>
+#include <tzplatform-config.h>
#include <utils.h>
struct app_labels_monitor {
int global_labels_file_watch;
int user_labels_file_watch;
bool fresh;
+ uid_t uid;
std::string user_label_file_path;
std::string global_label_file_path;
app_labels_monitor() : inotify(-1), global_labels_file_watch(-1), user_labels_file_watch(-1),
- fresh(true) {}
+ fresh(true), uid(-1) {}
};
-static lib_retcode apply_relabel_list(const std::string &global_label_file,
- const std::string &user_label_file)
+static lib_retcode inotify_add_watch_full(int fd, const char* pathname, uint32_t mask, int *wd)
+{
+ int inotify_fd = inotify_add_watch(fd, pathname, mask);
+ if (inotify_fd == -1) {
+ LogErrno("Inotify watch on file " << pathname);
+ return SECURITY_MANAGER_ERROR_WATCH_ADD_TO_FILE_FAILED;
+ }
+ *wd = inotify_fd;
+ return SECURITY_MANAGER_SUCCESS;
+}
+
+static lib_retcode monitor_repair_permissible_file(uid_t uid, const std::string &label_file_path, app_install_type install_type)
+{
+ LogWarning("Permissible file may be corrupted, sending request to repair: " << label_file_path);
+
+ ClientRequest request(SecurityModuleCall::REPAIR_PERMISSIBLE_FILE);
+ if (request.send(uid, install_type).failed()) {
+ return SECURITY_MANAGER_ERROR_SOCKET;
+ }
+ if (request.getStatus() != SECURITY_MANAGER_SUCCESS) {
+ return SECURITY_MANAGER_ERROR_FILE_INTEGRITY;
+ }
+
+ return SECURITY_MANAGER_SUCCESS;
+}
+
+static lib_retcode initialize_inotify(app_labels_monitor *monitor)
+{
+ lib_retcode ret_lib;
+ int ret = inotify_init();
+ if (ret == -1) {
+ LogErrno("Inotify init");
+ return SECURITY_MANAGER_ERROR_WATCH_ADD_TO_FILE_FAILED;
+ }
+ monitor->inotify = ret;
+ ret_lib = inotify_add_watch_full(monitor->inotify, monitor->global_label_file_path.c_str(),
+ IN_CLOSE_WRITE | IN_DELETE_SELF, &(monitor->global_labels_file_watch));
+ if (ret_lib != SECURITY_MANAGER_SUCCESS) {
+ security_manager_app_labels_monitor_finish(monitor);
+ return ret_lib;
+ }
+ ret_lib = inotify_add_watch_full(monitor->inotify, monitor->user_label_file_path.c_str(),
+ IN_CLOSE_WRITE | IN_DELETE_SELF, &(monitor->user_labels_file_watch));
+ if (ret_lib != SECURITY_MANAGER_SUCCESS) {
+ security_manager_app_labels_monitor_finish(monitor);
+ return ret_lib;
+ }
+
+ return SECURITY_MANAGER_SUCCESS;
+}
+
+static void readPermissibleFile(std::vector<std::string> &appLabels, const std::string &filePath, app_install_type installType, uid_t uid)
+{
+ try {
+ PermissibleSet::readLabelsFromPermissibleFile(filePath, appLabels);
+ } catch(PermissibleSet::PermissibleSetException::FileIntegrityError &e) {
+ lib_retcode ret = monitor_repair_permissible_file(uid, filePath, installType);
+ if (ret != SECURITY_MANAGER_SUCCESS) {
+ LogError("Repair failed: " << ret);
+ throw;
+ }
+ PermissibleSet::readLabelsFromPermissibleFile(filePath, appLabels);
+ }
+}
+
+static lib_retcode apply_relabel_list(app_labels_monitor *monitor)
{
std::vector<std::string> appLabels;
try {
- PermissibleSet::readLabelsFromPermissibleFile(global_label_file, appLabels);
- PermissibleSet::readLabelsFromPermissibleFile(user_label_file, appLabels);
- std::vector<const char*> temp;
+ readPermissibleFile(appLabels, monitor->global_label_file_path,
+ SM_APP_INSTALL_GLOBAL, TizenPlatformConfig::getUid(TZ_SYS_GLOBALAPP_USER));
+ readPermissibleFile(appLabels, monitor->user_label_file_path,
+ SM_APP_INSTALL_LOCAL, monitor->uid);
+
+ std::vector<const char *> temp;
std::transform(appLabels.begin(), appLabels.end(), std::back_inserter(temp),
- [] (std::string &label) {return label.c_str();});
+ [](std::string &label)
+ { return label.c_str(); });
if (smack_set_relabel_self(temp.data(), temp.size()) != 0) {
LogError("smack_set_relabel_self failed");
return SECURITY_MANAGER_SUCCESS;
}
-static lib_retcode inotify_add_watch_full(int fd, const char* pathname, uint32_t mask, int *wd)
-{
- int inotify_fd = inotify_add_watch(fd, pathname, mask);
- if (inotify_fd == -1) {
- LogErrno("Inotify watch on file " << pathname);
- return SECURITY_MANAGER_ERROR_WATCH_ADD_TO_FILE_FAILED;
- }
- *wd = inotify_fd;
- return SECURITY_MANAGER_SUCCESS;
-}
-
SECURITY_MANAGER_API
int security_manager_app_labels_monitor_init(app_labels_monitor **monitor)
{
LogWarning("Error input param \"monitor\"");
return SECURITY_MANAGER_ERROR_INPUT_PARAM;
}
- int ret;
- lib_retcode ret_lib;
*monitor = nullptr;
const std::string userFile =
PermissibleSet::getPermissibleFileLocation(uid, SM_APP_INSTALL_LOCAL);
-
- ret = inotify_init();
- if (ret == -1) {
- LogErrno("Inotify init");
- return SECURITY_MANAGER_ERROR_WATCH_ADD_TO_FILE_FAILED;
- }
- monitorPtr.get()->inotify = ret;
- ret_lib = inotify_add_watch_full(monitorPtr->inotify, globalFile.c_str(),
- IN_CLOSE_WRITE, &(monitorPtr->global_labels_file_watch));
- if (ret_lib != SECURITY_MANAGER_SUCCESS) {
- return ret_lib;
- }
- ret_lib = inotify_add_watch_full(monitorPtr->inotify, userFile.c_str(),
- IN_CLOSE_WRITE, &(monitorPtr->user_labels_file_watch));
- if (ret_lib != SECURITY_MANAGER_SUCCESS) {
- return ret_lib;
- }
+ monitorPtr->uid = uid;
monitorPtr->user_label_file_path = userFile;
monitorPtr->global_label_file_path = globalFile;
+
+ lib_retcode lib_ret = initialize_inotify(monitorPtr.get());
+ if (lib_ret != SECURITY_MANAGER_SUCCESS) {
+ LogErrno("Error during initializing inotify");
+ return lib_ret;
+ }
*monitor = monitorPtr.release();
return SECURITY_MANAGER_SUCCESS;
});
if (ret == -1) {
LogErrno("Inotify watch removal on file " << APPS_LABELS_FILE);
}
+ monitorPtr->global_labels_file_watch = -1;
}
if (monitorPtr->user_labels_file_watch != -1) {
int ret = inotify_rm_watch(monitorPtr->inotify, monitorPtr->user_labels_file_watch);
if (ret == -1) {
LogErrno("Inotify watch removal on file " << monitor->user_label_file_path);
}
+ monitorPtr->user_labels_file_watch = -1;
}
close(monitorPtr->inotify);
+ monitorPtr->inotify = -1;
}
return 0;
});
if (monitor->fresh) {
monitor->fresh = false;
- return apply_relabel_list(monitor->global_label_file_path,
- monitor->user_label_file_path);
+ return apply_relabel_list(monitor);
}
int avail;
((event.wd == monitor->global_labels_file_watch) ||
(event.wd == monitor->user_labels_file_watch))
){
- lib_retcode r = apply_relabel_list(monitor->global_label_file_path,
- monitor->user_label_file_path);
+ lib_retcode r = apply_relabel_list(monitor);
if (r != SECURITY_MANAGER_SUCCESS)
return r;
break;
}
+ if ((event.mask & IN_DELETE_SELF) &&
+ ((event.wd == monitor->global_labels_file_watch) ||
+ (event.wd == monitor->user_labels_file_watch))
+ ){
+ if (event.wd == monitor->global_labels_file_watch) {
+ lib_retcode r = inotify_add_watch_full(monitor->inotify, monitor->global_label_file_path.c_str(),
+ IN_CLOSE_WRITE | IN_DELETE_SELF, &(monitor->global_labels_file_watch));
+ if (r != SECURITY_MANAGER_SUCCESS) {
+ monitor->global_labels_file_watch = -1;
+ return r;
+ }
+
+ }
+ if (event.wd == monitor->user_labels_file_watch) {
+ lib_retcode r = inotify_add_watch_full(monitor->inotify, monitor->user_label_file_path.c_str(),
+ IN_CLOSE_WRITE | IN_DELETE_SELF, &(monitor->user_labels_file_watch));
+ if (r != SECURITY_MANAGER_SUCCESS) {
+ monitor->user_labels_file_watch = -1;
+ return r;
+ }
+ }
+ break;
+ }
}
return SECURITY_MANAGER_SUCCESS;
});
#include <vector>
#include <dpl/exception.h>
+#include <privilege_db.h>
#include <security-manager-types.h>
namespace SecurityManager {
*/
void readLabelsFromPermissibleFile(const std::string &nameFile, std::vector<std::string> &appLabels);
+/**
+ * Attempt to repair a possibly corrupted permissible file by reading directly from PrivilegeDb
+ * @throws FileOpenError
+ * @throws FileWriteError
+ *
+ * @param[in] uid user id
+ * @param[in] installationType type of installation (global or local)
+ */
+void repairPermissibleFile(uid_t uid, int installationType, PrivilegeDb &privilegeDb);
+
void initializeUserPermissibleFile(uid_t uid);
void removeUserPermissibleFile(uid_t uid);
GET_APP_MANIFEST_POLICY,
GET_PROCESS_LABEL,
PREPARE_APP,
+ REPAIR_PERMISSIBLE_FILE,
NOOP = 0x90,
};
Smack::Label &label, std::string &pkgName, PrepareAppFlags &prepareAppFlags,
std::vector<gid_t> &forbiddenGroups, std::vector<gid_t> &allowedGroups, std::vector<bool> &privPathsStatusVector);
+ /**
+ * Repair the possibly corrupted permissible file specified by input arguments
+ *
+ * @param[in] uid user id
+ * @param[in] installationType type of installation (global or local)
+ *
+ * @return API return code, as defined in protocols.h
+ */
+ int repairPermissibleFileForClient(uid_t uid, int installationType);
+
private:
int appInstallInitialChecks(const Credentials &creds,
app_inst_req &req);
int appUninstallSmackRules(app_inst_req &req, UninstallHelper &uh);
+ void tryUpdatePermissibleFile(uid_t uid, int installationType,
+ const std::vector<std::string> &newLabels,
+ const std::vector<std::string> &oldLabels);
+
bool authenticate(const Credentials &creds, const std::string &privilege);
bool authCheck(const Credentials &creds,
namespace SecurityManager {
namespace PermissibleSet {
-static const char* hashMarker = "-SHA-1";
-static const int hashMarkerLength = strlen(hashMarker);
-static const int hashLength = 40;
+static const char* tempFileName = "temp";
+static const char* hashMarker = "-SHA-1";
+static const int hashMarkerLength = strlen(hashMarker);
+static constexpr int hashLength = 40;
+
+class ScopedTemporaryFile
+{
+public:
+ const std::string path = std::string(LOCAL_STATE_INSTALL_DIR) + "/" + tempFileName;
+
+ ~ScopedTemporaryFile()
+ {
+ if (unlink(path.c_str()) != 0 && errno != ENOENT)
+ LogErrno("remove temporary permissible file");
+ }
+};
template <typename T>
static inline int getFd(T &fstream)
return ss.str();
}
+static void writeToPermissibleFile(const std::string &nameFile, std::ofstream &fstream, const std::stringstream &ss)
+{
+ auto content = ss.str();
+ auto hash = calculateHash(content);
+
+ fstream << hashMarker << " " << hash << '\n' << content;
+
+ if (fstream.bad()) {
+ LogAndThrowErrno(PermissibleSetException::FileWriteError, "write to file " << nameFile);
+ }
+ if (fstream.flush().fail()) {
+ LogAndThrowErrno(PermissibleSetException::FileWriteError, "fflush " << nameFile);
+ }
+ if (fsync(getFd(fstream)) == -1) {
+ LogAndThrowErrno(PermissibleSetException::FileWriteError, "fsync " << nameFile);
+ }
+}
+
void verifyFileIntegrity(const std::string &nameFile, std::ifstream &fstream)
{
auto fileSize = std::filesystem::file_size(nameFile);
labelsForUser.push_back(l);
}
- std::ofstream fstream;
- openAndLockNameFile(nameFile, fstream);
- markPermissibleFileValid(getFd(fstream), nameFile, false);
-
std::stringstream ss;
for (auto &label : labelsForUser) {
ss << label << '\n';
}
- auto content = ss.str();
- auto hash = calculateHash(content);
-
- fstream << hashMarker << "\n" << hash << '\n' << content;
-
- if (fstream.bad())
- LogAndThrowErrno(PermissibleSetException::PermissibleSetException::FileWriteError,
- "write to file " << nameFile);
- if (fstream.flush().fail())
- LogAndThrowErrno(PermissibleSetException::FileWriteError, "fflush " << nameFile);
- if (fsync(getFd(fstream)) == -1)
- LogAndThrowErrno(PermissibleSetException::FileWriteError, "fsync " << nameFile);
+ std::ofstream fstream;
+ openAndLockNameFile(nameFile, fstream);
+ markPermissibleFileValid(getFd(fstream), nameFile, false);
+ writeToPermissibleFile(nameFile, fstream, ss);
markPermissibleFileValid(getFd(fstream), nameFile, true);
}
LogAndThrowErrno(PermissibleSetException::FileReadError, "reading file " << nameFile);
}
+void repairPermissibleFile(uid_t uid, int installationType, PrivilegeDb &privilegeDb)
+{
+ std::string nameFile = getPermissibleFileLocation(uid, installationType);
+ std::vector<std::string> appNames;
+ privilegeDb.GetUserApps(uid, appNames);
+
+ std::stringstream ss;
+ for (auto &appName : appNames) {
+ std::string pkgName;
+ privilegeDb.GetAppPkgName(appName, pkgName);
+ bool isPkgHybrid = privilegeDb.IsPackageHybrid(pkgName);
+
+ ss << SmackLabels::generateProcessLabel(appName, pkgName, isPkgHybrid) << '\n';
+ }
+ {
+ ScopedTemporaryFile temporaryFile;
+
+ std::ofstream fstream(temporaryFile.path);
+ if (!fstream.is_open())
+ LogAndThrowErrno(PermissibleSetException::FileOpenError, "open file " << nameFile);
+
+ writeToPermissibleFile(temporaryFile.path, fstream, ss);
+ if (rename(temporaryFile.path.c_str(), nameFile.c_str()) != 0)
+ ThrowErrno(PermissibleSetException::FileWriteError,
+ "move temporary file");
+ }
+}
+
void initializeUserPermissibleFile(uid_t uid)
{
std::string nameFile = getPermissibleFileLocation(uid, SM_APP_INSTALL_LOCAL);
SM_CODE_DESCRIBE(SecurityModuleCall::GET_APP_MANIFEST_POLICY);
SM_CODE_DESCRIBE(SecurityModuleCall::GET_PROCESS_LABEL);
SM_CODE_DESCRIBE(SecurityModuleCall::PREPARE_APP);
+ SM_CODE_DESCRIBE(SecurityModuleCall::REPAIR_PERMISSIBLE_FILE);
SM_CODE_DESCRIBE(SecurityModuleCall::NOOP);
default: return "Code not defined";
}
return SECURITY_MANAGER_SUCCESS;
}
+void ServiceImpl::tryUpdatePermissibleFile(uid_t uid, int installationType,
+ const std::vector<std::string> &newLabels,
+ const std::vector<std::string> &oldLabels)
+{
+ try {
+ PermissibleSet::updatePermissibleFile(uid, installationType, newLabels, oldLabels);
+ } catch (const PermissibleSet::PermissibleSetException::FileIntegrityError &e) {
+ LogWarning("Permissible file may be corrupted, attempting repair: " << e.DumpToString());
+ PermissibleSet::repairPermissibleFile(uid, installationType, m_privilegeDb);
+ PermissibleSet::updatePermissibleFile(uid, installationType, newLabels, oldLabels);
+ }
+}
+
int ServiceImpl::appInstall(const Credentials &creds, app_inst_req &req)
{
int ret;
getPkgLabels(req.pkgName, newLabels);
// update permissible set
- PermissibleSet::updatePermissibleFile(req.uid, req.installationType, newLabels, oldLabels);
+ tryUpdatePermissibleFile(req.uid, req.installationType, newLabels, oldLabels);
// label paths
ret = labelPaths(req.pkgPaths,
} catch (const CynaraException::Base &e) {
LogError("Error while setting Cynara rules for application: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+ } catch (const PermissibleSet::PermissibleSetException::FileIntegrityError &e) {
+ LogError("Error while updating permissible file - integrity error has been detected but it could not be fixed: " << e.DumpToString());
+ return SECURITY_MANAGER_ERROR_FILE_INTEGRITY;
} catch (const PermissibleSet::PermissibleSetException::Base &e) {
LogError("Error while updating permissible file: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SERVER_ERROR;
getPkgLabels(req.pkgName, newLabels);
// update permissible set
- PermissibleSet::updatePermissibleFile(req.uid, req.installationType, newLabels, oldLabels);
+ tryUpdatePermissibleFile(req.uid, req.installationType, newLabels, oldLabels);
// label paths
ret = labelPaths(req.pkgPaths,
} catch (const CynaraException::Base &e) {
LogError("Error while setting Cynara rules for application: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+ } catch (const PermissibleSet::PermissibleSetException::FileIntegrityError &e) {
+ LogError("Error while updating permissible file - integrity error has been detected but it could not be fixed: " << e.DumpToString());
+ return SECURITY_MANAGER_ERROR_FILE_INTEGRITY;
} catch (const PermissibleSet::PermissibleSetException::Base &e) {
LogError("Error while updating permissible file: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SERVER_ERROR;
getPkgLabels(req.pkgName, newLabels);
// update permissible set
- PermissibleSet::updatePermissibleFile(req.uid, req.installationType, newLabels, oldLabels);
+ tryUpdatePermissibleFile(req.uid, req.installationType, newLabels, oldLabels);
// remove and merge Smack rules for apps and pkg
return appUninstallSmackRules(req, uh);
} catch (const PrivilegeDb::Exception::Base &e) {
LogError("Error while removing application info from database: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SERVER_ERROR;
+ } catch (const PermissibleSet::PermissibleSetException::FileIntegrityError &e) {
+ LogError("Error while updating permissible file - integrity error has been detected but it could not be fixed: " << e.DumpToString());
+ return SECURITY_MANAGER_ERROR_FILE_INTEGRITY;
} catch (const PermissibleSet::PermissibleSetException::Base &e) {
LogError("Error while updating permissible file: " << e.DumpToString());
return SECURITY_MANAGER_ERROR_SERVER_ERROR;
}
}
+int ServiceImpl::repairPermissibleFileForClient(uid_t uid, int installationType)
+{
+ try {
+ PermissibleSet::repairPermissibleFile(uid, installationType, m_privilegeDb);
+ }
+ catch (PermissibleSet::PermissibleSetException::Base &e){
+ LogErrno("error while repairing the permissible file: " << e.DumpToString());
+ return SECURITY_MANAGER_ERROR_FILE_INTEGRITY;
+ } catch (...){
+ LogErrno("other error during permissible file repair ");
+ return SECURITY_MANAGER_ERROR_UNKNOWN;
+ }
+
+ return SECURITY_MANAGER_SUCCESS;
+}
+
} /* namespace SecurityManager */
* @param creds credentials of the requesting process
*/
void prepareApp(MessageBuffer &buffer, const Credentials &creds);
+
+ /**
+ * Repair the requested Smack permissible file by fetching data from PrivilegeDb
+ *
+ * @param buffer Input/output message buffer
+ */
+ void processRepairPermissibleFile(MessageBuffer &buffer);
};
} // namespace SecurityManager
case SecurityModuleCall::PREPARE_APP:
prepareApp(msg.buffer, msg.creds);
break;
+ case SecurityModuleCall::REPAIR_PERMISSIBLE_FILE:
+ processRepairPermissibleFile(msg.buffer);
+ break;
default:
LogError("Invalid call: " << call_type_int);
Throw(ServiceException::InvalidAction);
Serialization::Serialize(buffer, forbiddenGroups, allowedGroups, privPathsStatusVector, label, pkgName, prepareAppFlags);
}
+void Service::processRepairPermissibleFile(MessageBuffer &buffer)
+{
+ uid_t uid;
+ int installationType;
+
+ Deserialization::Deserialize(buffer, uid, installationType);
+
+ int ret = m_serviceImpl.repairPermissibleFileForClient(uid, installationType);
+
+ buffer.ModeStreaming();
+ Serialization::Serialize(buffer, ret);
+}
+
} // namespace SecurityManager