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 <skinsbur...@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 <khlebni...@openvz.org>
    
    Signed-off-by: Cyrill Gorcunov <gorcu...@openvz.org>
    
    Signed-off-by: Stanislav Kinsburskiy <skinsbur...@virtuozzo.com>
    
    (cherry-picked from vz8 commit 294d1d1c97258748b13e7663ca470f97d4b90328)
    Signed-off-by: Pavel Tikhomirov <ptikhomi...@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)
_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to