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