[Devel] [PATCH RHEL COMMIT] ve/kernfs: add new interface to control per-VE nodes visibility
Konstantin Khorenko
khorenko at virtuozzo.com
Wed Sep 22 14:50:54 MSK 2021
The commit is pushed to "branch-rh9-5.14.vz9.1.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after ark-5.14
------>
commit 05ef37cf58deffdef58e1cfaf5fa4fd71ff15e38
Author: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>
Date: Wed Sep 22 14:50:54 2021 +0300
ve/kernfs: add new interface to control per-VE nodes visibility
This patch allows to set kernfs nodes visibility via kernfs_perms_* helpers.
There is an internal kernel interface. I.e. it should to be wrapped by actual
file operations for a desired file system.
These four should be used for sequentialpremissions reading:
void *kernfs_perms_start(struct seq_file *m, loff_t *ppos,
struct kernfs_node *root, struct kmapset_key *key);
void *kernfs_perms_next(struct seq_file *m, void *v, loff_t *ppos,
struct kmapset_key *key);
void kernfs_perms_stop(struct seq_file *m, void *v);
int kernfs_perms_show(struct seq_file *m, void *v, struct kmapset_key *key);
And this one for permissions writing:
ssize_t kernfs_perms_write(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off,
struct kernfs_node *root, struct kmapset_key *key);
They do all the job. All is needed is to pass file system root and pointer
per-ve key.
Permissions are controlled via human-readable interface with the following
format:
<path> [r][w][x][-]
Helpers accepts multi-line input, so they are 'cat' compatible.
An example of default config for sysfs:
/ rx
block rx
class rx
class/block rx
class/net rx
class/tty rx
class/mem rx
devices rx
devices/virtual rx
devices/virtual/tty rx
devices/virtual/tty/tty rx
devices/virtual/tty/tty/uevent rw
devices/virtual/tty/tty/dev r
devices/virtual/tty/console rx
devices/virtual/tty/console/uevent rw
devices/virtual/tty/console/dev r
devices/virtual/tty/ptmx rx
devices/virtual/tty/ptmx/uevent rw
devices/virtual/tty/ptmx/dev r
devices/virtual/tty/tty0 rx
devices/virtual/tty/tty0/uevent rw
devices/virtual/tty/tty0/dev r
devices/virtual/tty/tty1 rx
devices/virtual/tty/tty1/uevent rw
devices/virtual/tty/tty1/dev r
devices/virtual/tty/tty2 rx
devices/virtual/tty/tty2/uevent rw
devices/virtual/tty/tty2/dev r
devices/virtual/mem rx
devices/virtual/mem/null rx
devices/virtual/mem/null/uevent rw
devices/virtual/mem/null/dev r
devices/virtual/mem/zero rx
devices/virtual/mem/zero/uevent rw
devices/virtual/mem/zero/dev r
devices/virtual/mem/full rx
devices/virtual/mem/full/uevent rw
devices/virtual/mem/full/dev r
devices/virtual/mem/random rx
devices/virtual/mem/random/uevent rw
devices/virtual/mem/random/dev r
devices/virtual/mem/urandom rx
devices/virtual/mem/urandom/uevent rw
devices/virtual/mem/urandom/dev r
devices/virtual/net rx
devices/system rx
devices/system/cpu rx
devices/system/cpu/cpu0 rx
devices/system/cpu/cpu1 rx
dev rx
dev/block rx
dev/char rx
fs rx
fs/cgroup rx
kernel rx
kernel/uevent_seqnum r
Signed-off-by: Konstantin Khlebnikov <khlebnikov at openvz.org>
Signed-off-by: Cyrill Gorcunov <gorcunov at openvz.org>
Signed-off-by: Stanislav Kinsburskiy <skinsbursky at virtuozzo.com>
(cherry-picked from vz8 commit 294d1d1c97258748b13e7663ca470f97d4b90328)
Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
---
fs/kernfs/ve.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++
include/linux/kernfs-ve.h | 13 +++
2 files changed, 239 insertions(+)
diff --git a/fs/kernfs/ve.c b/fs/kernfs/ve.c
index 383724fb2dae..8abb020de40f 100644
--- a/fs/kernfs/ve.c
+++ b/fs/kernfs/ve.c
@@ -126,3 +126,229 @@ bool kernfs_d_visible(struct kernfs_node *kn, struct kernfs_super_info *info)
return !!kmapset_get_value(kn->ve_perms_map,
kernfs_info_perms_key(info));
}
+
+#define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb)
+
+static struct kernfs_node *kernfs_next_recursive(struct kernfs_node *kn)
+{
+ struct rb_node *node;
+
+ if (kernfs_type(kn) == KERNFS_DIR &&
+ !RB_EMPTY_ROOT(&kn->dir.children)) {
+ return rb_to_kn(rb_first(&kn->dir.children));
+ }
+
+ do {
+ node = rb_next(&kn->rb);
+ if (node)
+ return rb_to_kn(node);
+ kn = kn->parent;
+ } while (kn);
+
+ return kn;
+}
+
+static bool kernfs_perms_shown(struct ve_struct *ve, struct kernfs_node *kn,
+ struct kmapset_key *key)
+{
+ if (ve_is_super(ve))
+ return kn->ve_perms_map->default_value != 0;
+ return kmapset_lookup(kn->ve_perms_map, key) != NULL;
+}
+
+void *kernfs_perms_start(struct seq_file *m, loff_t *ppos,
+ struct kernfs_node *root, struct kmapset_key *key)
+{
+ struct ve_struct *ve = css_to_ve(seq_css(m));
+ struct kernfs_node *kn;
+ loff_t pos = *ppos;
+
+ mutex_lock(&kernfs_mutex);
+ for (kn = root; kn; kn = kernfs_next_recursive(kn)) {
+ if (kernfs_perms_shown(ve, kn, key) && !pos--)
+ break;
+ };
+ return kn;
+}
+
+void *kernfs_perms_next(struct seq_file *m, void *v, loff_t *ppos,
+ struct kmapset_key *key)
+{
+ struct ve_struct *ve = css_to_ve(seq_css(m));
+ struct kernfs_node *kn = v;
+
+ (*ppos)++;
+ while ((kn = kernfs_next_recursive(kn))) {
+ if (kernfs_perms_shown(ve, kn, key))
+ break;
+ };
+ return kn;
+}
+
+void kernfs_perms_stop(struct seq_file *m, void *v)
+{
+ mutex_unlock(&kernfs_mutex);
+}
+
+int kernfs_perms_show(struct seq_file *m, void *v, struct kmapset_key *key)
+{
+ struct ve_struct *ve = css_to_ve(seq_css(m));
+ struct kernfs_node *kn = v;
+ char *buf;
+ size_t size, len, off;
+ int mask;
+
+ if (ve_is_super(ve))
+ mask = kn->ve_perms_map->default_value;
+ else
+ mask = kmapset_get_value(kn->ve_perms_map, key);
+
+ size = seq_get_buf(m, &buf);
+ if (size) {
+ off = size;
+ do {
+ len = strlen(kn->name);
+ if (len >= off) {
+ seq_commit(m, -1);
+ return 0;
+ }
+ if (kernfs_type(kn) == KERNFS_DIR)
+ buf[--off] = '/';
+ off -= len;
+ memcpy(buf + off, kn->name, len);
+ kn = kn->parent;
+ } while (kn && kn != kernfs_root(kn)->kn);
+ memmove(buf, buf + off, size - off);
+ seq_commit(m, size - off);
+ }
+
+ seq_putc(m, ' ');
+
+ if (!mask)
+ seq_putc(m, '-');
+ if (mask & MAY_READ)
+ seq_putc(m, 'r');
+ if (mask & MAY_WRITE)
+ seq_putc(m, 'w');
+ if (mask & MAY_EXEC)
+ seq_putc(m, 'x');
+
+ seq_putc(m, '\n');
+
+ return 0;
+}
+
+static int kernfs_perms_set(char *path, struct ve_struct *ve, int mask,
+ struct kernfs_node *root, struct kmapset_key *key)
+{
+ struct kernfs_node *kn = root, *nkn;
+ struct kmapset_map *map = NULL;
+ char *sep = path, *dname;
+ int ret;
+
+ kernfs_get(kn);
+ do {
+ dname = sep;
+
+ sep = strchr(sep, '/');
+ if (sep)
+ *sep++ = 0;
+
+ if (!*dname)
+ break;
+
+ nkn = kernfs_find_and_get(kn, dname);
+ if (!nkn) {
+ ret = -ENOENT;
+ goto out;
+ }
+
+ kernfs_put(kn);
+ kn = nkn;
+ } while (sep);
+
+ ret = -ENOMEM;
+ map = kmapset_dup(kn->ve_perms_map);
+ if (!map)
+ goto out_put;
+
+ ret = 0;
+ if (ve_is_super(ve)) {
+ kmapset_set_default(map, mask > 0 ? mask : 0);
+ } else if (mask < 0) {
+ kmapset_del_value(map, key);
+ } else {
+ ret = kmapset_set_value(map, key, mask);
+ }
+
+ if (!ret) {
+ map = kmapset_commit(map);
+ swap(map, kn->ve_perms_map);
+ }
+
+out_put:
+ kmapset_put(map);
+out:
+ kernfs_put(kn);
+ return ret;
+}
+
+static int kernfs_perms_line(struct ve_struct *ve, char *line,
+ struct kernfs_node *root, struct kmapset_key *key)
+{
+ int mask = 0;
+ char *p;
+
+ p = strpbrk(line, " \t");
+ if (!p)
+ return -EINVAL;
+ *p++ = 0;
+ p = skip_spaces(p);
+ while (1) {
+ switch (*p++) {
+ case 'r':
+ mask |= MAY_READ;
+ break;
+ case 'w':
+ mask |= MAY_WRITE;
+ break;
+ case 'x':
+ mask |= MAY_EXEC;
+ break;
+ case '-':
+ mask = -1;
+ break;
+ case 0:
+ return kernfs_perms_set(line, ve, mask,
+ root, key);
+ default:
+ return -EINVAL;
+ }
+ }
+}
+
+ssize_t kernfs_perms_write(struct kernfs_open_file *of,
+ char *buf, size_t nbytes, loff_t off,
+ struct kernfs_node *root, struct kmapset_key *key)
+{
+ struct ve_struct *ve = css_to_ve(of_css(of));
+ char *line, *next = buf;
+ int ret = -EINVAL;
+
+ do {
+ line = skip_spaces(next);
+ if (!*line)
+ break;
+
+ next = strchr(line, '\n');
+ if (next)
+ *next++ = '\0';
+
+ if (*line != '#') {
+ ret = kernfs_perms_line(ve, line, root, key);
+ if (ret)
+ break;
+ }
+ } while (next);
+ return ret ? ret : nbytes;
+}
diff --git a/include/linux/kernfs-ve.h b/include/linux/kernfs-ve.h
index 325ff6a22f33..11420351b3dd 100644
--- a/include/linux/kernfs-ve.h
+++ b/include/linux/kernfs-ve.h
@@ -18,6 +18,19 @@ struct dentry;
int kernfs_init_ve_perms(struct kernfs_root *root,
struct kmapset_set *perms_set);
void kernfs_set_ve_perms(struct dentry *root, off_t key_off);
+
+void *kernfs_perms_start(struct seq_file *m, loff_t *ppos,
+ struct kernfs_node *root, struct kmapset_key *key);
+void *kernfs_perms_next(struct seq_file *m, void *v, loff_t *ppos,
+ struct kmapset_key *key);
+void kernfs_perms_stop(struct seq_file *m, void *v);
+
+int kernfs_perms_show(struct seq_file *m, void *v, struct kmapset_key *key);
+
+ssize_t kernfs_perms_write(struct kernfs_open_file *of,
+ char *buf, size_t nbytes, loff_t off,
+ struct kernfs_node *root, struct kmapset_key *key);
+
#else /* CONFIG_VE */
static inline int kernfs_init_ve_perms(struct kernfs_root *root,
struct kmapset_set *perms_set)
More information about the Devel
mailing list