summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWaLyong Cho <walyong.cho@samsung.com>2015-06-10 11:33:00 +0900
committerƁukasz Stelmach <l.stelmach@samsung.com>2017-02-24 16:08:14 +0100
commit32c66656d0413fdb7dfb9fce07a158498c110475 (patch)
tree6f1d14ad1da4fa803de4c70627b1cdb85c1ebe55 /src
parent0f2ef75554bf3426e253f9bfef0d8b1f05851311 (diff)
downloadsystemd-32c66656d0413fdb7dfb9fce07a158498c110475.tar.gz
systemd-32c66656d0413fdb7dfb9fce07a158498c110475.tar.bz2
systemd-32c66656d0413fdb7dfb9fce07a158498c110475.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>
Diffstat (limited to 'src')
-rw-r--r--src/core/smack-setup.c94
1 files changed, 87 insertions, 7 deletions
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
index 5a6d11cfa1..f22d6a242f 100644
--- a/src/core/smack-setup.c
+++ b/src/core/smack-setup.c
@@ -210,11 +210,11 @@ static int write_netlabel_rules(const char* srcdir) {
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 */
}
@@ -225,11 +225,14 @@ static int write_netlabel_rules(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;
}
@@ -238,21 +241,98 @@ static int write_netlabel_rules(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_errno(errno, "Failed to write line to /sys/fs/smackfs/netlabel");
break;
}
- 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 /sys/fs/smackfs/netlabel: %m");