summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWaLyong Cho <walyong.cho@samsung.com>2015-06-10 11:33:00 +0900
committerSangjung Woo <sangjung.woo@samsung.com>2015-07-08 10:11:59 +0900
commit7a0f1e20a0cd3644e72cac40463a451d1966f885 (patch)
tree9edd65598e54965186401f41f3afd24f7b62d760
parent5d165975678866b57f08004b4fd78db0251bfb0f (diff)
downloadsystemd-7a0f1e20a0cd3644e72cac40463a451d1966f885.tar.gz
systemd-7a0f1e20a0cd3644e72cac40463a451d1966f885.tar.bz2
systemd-7a0f1e20a0cd3644e72cac40463a451d1966f885.zip
smack: support smack access change-rule
Smack is also able to have modification rules of existing rules. In this case, the rule has additional argument to modify previous rule. /sys/fs/smackfs/load2 node can only take three arguments: subject object access. So if modification rules are written to /sys/fs/smackfs/load2, EINVAL error is happen. Those modification rules have to be written to /sys/fs/smackfs/change-rule. To distinguish access with operation of cipso2, split write_rules() for each operation. And, in write access rules, parse the rule and if the rule has four argument then write into /sys/fs/smackfs/change-rule. https://lwn.net/Articles/532340/ fwrite() or fputs() are fancy functions to write byte stream such like regular file. But special files on linux such like proc, sysfs are not stream of bytes. Those special files on linux have to be written with specific size. By this reason, in some of many case, fputs() was failed to write buffer to smack load2 node. The write operation for the smack nodes should be performed with write(). Origin: https://github.com/systemd/systemd/commit/6656aefb Change-Id: Ied3eb195b86514525cb1c6904a7a7b66d1bccb52 Signed-off-by: Sangjung Woo <sangjung.woo@samsung.com>
-rw-r--r--src/core/smack-setup.c151
1 files changed, 109 insertions, 42 deletions
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
index 33dc1ca331..05b1aec5f7 100644
--- a/src/core/smack-setup.c
+++ b/src/core/smack-setup.c
@@ -40,32 +40,35 @@
#include "log.h"
#include "label.h"
-#define SMACK_CONFIG "/etc/smack/accesses.d/"
-#define CIPSO_CONFIG "/etc/smack/cipso.d/"
-#define NETLABEL_CONFIG "/etc/smack/netlabel.d/"
-
#ifdef HAVE_SMACK
-static int write_rules(const char* dstpath, const char* srcdir) {
- _cleanup_fclose_ FILE *dst = NULL;
+static int write_access2_rules(const char* srcdir) {
+ _cleanup_close_ int load2_fd = -1, change_fd = -1;
_cleanup_closedir_ DIR *dir = NULL;
struct dirent *entry;
char buf[NAME_MAX];
int dfd = -1;
int r = 0;
- dst = fopen(dstpath, "we");
- if (!dst) {
+ load2_fd = open("/sys/fs/smackfs/load2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+ if (load2_fd < 0) {
+ if (errno != ENOENT)
+ log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/load2': %m");
+ return -errno; /* negative error */
+ }
+
+ change_fd = open("/sys/fs/smackfs/change-rule", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+ if (change_fd < 0) {
if (errno != ENOENT)
- log_warning_errno(errno, "Failed to open %s: %m", dstpath);
+ log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/change-rule': %m");
return -errno; /* negative error */
}
- /* write rules to dst from every file in the directory */
+ /* write rules to load2 or change-rule from every file in the directory */
dir = opendir(srcdir);
if (!dir) {
if (errno != ENOENT)
- log_warning_errno(errno, "Failed to opendir %s: %m", srcdir);
+ log_warning_errno(errno, "Failed to opendir '%s': %m", srcdir);
return errno; /* positive on purpose */
}
@@ -76,11 +79,14 @@ static int write_rules(const char* dstpath, const char* srcdir) {
int fd;
_cleanup_fclose_ FILE *policy = NULL;
+ if (!dirent_is_file(entry))
+ continue;
+
fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
if (fd < 0) {
if (r == 0)
r = -errno;
- log_warning_errno(errno, "Failed to open %s: %m", entry->d_name);
+ log_warning_errno(errno, "Failed to open '%s': %m", entry->d_name);
continue;
}
@@ -89,30 +95,108 @@ static int write_rules(const char* dstpath, const char* srcdir) {
if (r == 0)
r = -errno;
safe_close(fd);
- log_error_errno(errno, "Failed to open %s: %m", entry->d_name);
+ log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
continue;
}
/* load2 write rules in the kernel require a line buffered stream */
FOREACH_LINE(buf, policy,
- log_error_errno(errno, "Failed to read line from %s: %m",
+ log_error(errno, "Failed to read line from '%s': %m",
entry->d_name)) {
- if (!fputs(buf, dst)) {
+
+ _cleanup_free_ char *sbj = NULL, *obj = NULL, *acc1 = NULL, *acc2 = NULL;
+
+ if (isempty(truncate_nl(buf)))
+ continue;
+
+ /* if 3 args -> load rule : subject object access1 */
+ /* if 4 args -> change rule : subject object access1 access2 */
+ if (sscanf(buf, "%ms %ms %ms %ms", &sbj, &obj, &acc1, &acc2) < 3) {
+ log_error_errno(errno, "Failed to parse rule '%s' in '%s', ignoring.", buf, entry->d_name);
+ continue;
+ }
+
+ if (write(isempty(acc2) ? load2_fd : change_fd, buf, strlen(buf)) < 0) {
if (r == 0)
- r = -EINVAL;
- log_error("Failed to write line to %s", dstpath);
- break;
+ r = -errno;
+ log_error_errno(errno, "Failed to write '%s' to '%s' in '%s'",
+ buf, isempty(acc2) ? "/sys/fs/smackfs/load2" : "/sys/fs/smackfs/change-rule", entry->d_name);
}
- if (fflush(dst)) {
+ }
+ }
+
+ return r;
+}
+
+static int write_cipso2_rules(const char* srcdir) {
+ _cleanup_close_ int cipso2_fd = -1;
+ _cleanup_closedir_ DIR *dir = NULL;
+ struct dirent *entry;
+ char buf[NAME_MAX];
+ int dfd = -1;
+ int r = 0;
+
+ cipso2_fd = open("/sys/fs/smackfs/cipso2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
+ if (cipso2_fd < 0) {
+ if (errno != ENOENT)
+ log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/cipso2': %m");
+ return -errno; /* negative error */
+ }
+
+ /* write rules to cipso2 from every file in the directory */
+ dir = opendir(srcdir);
+ if (!dir) {
+ if (errno != ENOENT)
+ log_warning_errno(errno, "Failed to opendir '%s': %m", srcdir);
+ return errno; /* positive on purpose */
+ }
+
+ dfd = dirfd(dir);
+ assert(dfd >= 0);
+
+ FOREACH_DIRENT(entry, dir, return 0) {
+ int fd;
+ _cleanup_fclose_ FILE *policy = NULL;
+
+ if (!dirent_is_file(entry))
+ continue;
+
+ fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
+ if (fd < 0) {
+ if (r == 0)
+ r = -errno;
+ log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
+ continue;
+ }
+
+ policy = fdopen(fd, "re");
+ if (!policy) {
+ if (r == 0)
+ r = -errno;
+ safe_close(fd);
+ log_error_errno(errno, "Failed to open '%s': %m", entry->d_name);
+ continue;
+ }
+
+ /* cipso2 write rules in the kernel require a line buffered stream */
+ FOREACH_LINE(buf, policy,
+ log_error_errno(errno, "Failed to read line from '%s': %m",
+ entry->d_name)) {
+
+ if (isempty(truncate_nl(buf)))
+ continue;
+
+ if (write(cipso2_fd, buf, strlen(buf)) < 0) {
if (r == 0)
r = -errno;
- log_error_errno(errno, "Failed to flush writes to %s: %m", dstpath);
+ log_error_errno(errno, "Failed to write '%s' to '/sys/fs/smackfs/cipso2' in '%s'",
+ buf, entry->d_name);
break;
}
}
}
- return r;
+ return r;
}
#endif
@@ -125,13 +209,13 @@ int mac_smack_setup(bool *loaded_policy) {
assert(loaded_policy);
- r = write_rules("/sys/fs/smackfs/load2", SMACK_CONFIG);
+ r = write_access2_rules("/etc/smack/accesses.d/");
switch(r) {
case -ENOENT:
log_debug("Smack is not enabled in the kernel.");
return 0;
case ENOENT:
- log_debug("Smack access rules directory " SMACK_CONFIG " not found");
+ log_debug("Smack access rules directory '/etc/smack/accesses.d/' not found");
return 0;
case 0:
log_info("Successfully loaded Smack policies.");
@@ -162,13 +246,13 @@ int mac_smack_setup(bool *loaded_policy) {
"127.0.0.1 -CIPSO", strerror(-r));
#endif
- r = write_rules("/sys/fs/smackfs/cipso2", CIPSO_CONFIG);
+ r = write_cipso2_rules("/etc/smack/cipso.d/");
switch(r) {
case -ENOENT:
log_debug("Smack/CIPSO is not enabled in the kernel.");
return 0;
case ENOENT:
- log_debug("Smack/CIPSO access rules directory " CIPSO_CONFIG " not found");
+ log_debug("Smack/CIPSO access rules directory '/etc/smack/cipso.d/' not found");
break;
case 0:
log_info("Successfully loaded Smack/CIPSO policies.");
@@ -179,23 +263,6 @@ int mac_smack_setup(bool *loaded_policy) {
break;
}
- r = write_rules("/sys/fs/smackfs/netlabel", NETLABEL_CONFIG);
- switch(r) {
- case -ENOENT:
- log_debug("Smack/CIPSO is not enabled in the kernel.");
- return 0;
- case ENOENT:
- log_debug("Smack network host rules directory " NETLABEL_CONFIG " not found");
- break;
- case 0:
- log_info("Successfully loaded Smack network host rules.");
- break;
- default:
- log_warning("Failed to load Smack network host rules: %s, ignoring.",
- strerror(abs(r)));
- break;
- }
-
*loaded_policy = true;
#endif