From 463a69657505ad5db58a9a5ccaa96ffb8939187a Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Wed, 21 Jun 2017 13:56:53 -0700 Subject: [PATCH] scoutfs: add value length limit Add a relatively small universal value size limit. This will be needed by more dense item packing to predict the worst case padding to avoid full items crossing block boundaries. We refactor the existing symlink and xattr item value limit to use this new limit. Signed-off-by: Zach Brown --- kmod/src/count.h | 2 +- kmod/src/dir.c | 10 +++++----- kmod/src/format.h | 21 ++++++++++++--------- kmod/src/item.c | 20 ++++++++++++++++++++ 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/kmod/src/count.h b/kmod/src/count.h index b763cc2b..4198dbf5 100644 --- a/kmod/src/count.h +++ b/kmod/src/count.h @@ -54,7 +54,7 @@ static inline void scoutfs_count_dirents(struct scoutfs_item_count *cnt, static inline void scoutfs_count_sym_target(struct scoutfs_item_count *cnt, unsigned size) { - unsigned nr = DIV_ROUND_UP(size, SCOUTFS_SYMLINK_MAX_VAL_SIZE); + unsigned nr = DIV_ROUND_UP(size, SCOUTFS_MAX_VAL_SIZE); cnt->items += nr; cnt->keys += nr * sizeof(struct scoutfs_symlink_key); diff --git a/kmod/src/dir.c b/kmod/src/dir.c index 04461e75..52448cd5 100644 --- a/kmod/src/dir.c +++ b/kmod/src/dir.c @@ -661,7 +661,7 @@ enum { SYM_DELETE, }; static int symlink_item_ops(struct super_block *sb, int op, u64 ino, - const char *target, int size) + const char *target, size_t size) { struct scoutfs_symlink_key skey; struct scoutfs_key_buf key; @@ -671,15 +671,15 @@ static int symlink_item_ops(struct super_block *sb, int op, u64 ino, int ret; int i; - if (WARN_ON_ONCE(size <= 0 || size > SCOUTFS_SYMLINK_MAX_SIZE || + if (WARN_ON_ONCE(size == 0 || size > SCOUTFS_SYMLINK_MAX_SIZE || op > SYM_DELETE)) return -EINVAL; - nr = DIV_ROUND_UP(size, SCOUTFS_SYMLINK_MAX_VAL_SIZE); + nr = DIV_ROUND_UP(size, SCOUTFS_MAX_VAL_SIZE); for (i = 0; i < nr; i++) { init_symlink_key(&key, &skey, ino, i); - bytes = min(size, SCOUTFS_SYMLINK_MAX_VAL_SIZE); + bytes = min(size, SCOUTFS_MAX_VAL_SIZE); scoutfs_kvec_init(val, (void *)target, bytes); if (op == SYM_CREATE) @@ -691,7 +691,7 @@ static int symlink_item_ops(struct super_block *sb, int op, u64 ino, if (ret) break; - target += SCOUTFS_SYMLINK_MAX_VAL_SIZE; + target += SCOUTFS_MAX_VAL_SIZE; size -= bytes; } diff --git a/kmod/src/format.h b/kmod/src/format.h index fc36d50e..c511d51a 100644 --- a/kmod/src/format.h +++ b/kmod/src/format.h @@ -260,8 +260,6 @@ struct scoutfs_symlink_key { __u8 nr; } __packed; -#define SCOUTFS_SYMLINK_MAX_VAL_SIZE 200 - struct scoutfs_betimespec { __be64 sec; __be32 nsec; @@ -377,13 +375,6 @@ struct scoutfs_dirent { /* S32_MAX avoids the (int) sign bit and might avoid sloppy bugs */ #define SCOUTFS_LINK_MAX S32_MAX -#define SCOUTFS_XATTR_MAX_NAME_LEN 255 -#define SCOUTFS_XATTR_MAX_SIZE 65536 -#define SCOUTFS_XATTR_PART_SIZE \ - (SCOUTFS_BLOCK_SIZE - sizeof(struct scoutfs_xattr_val_header)) -#define SCOUTFS_XATTR_MAX_PARTS \ - DIV_ROUND_UP(SCOUTFS_XATTR_MAX_SIZE, SCOUTFS_XATTR_PART_SIZE) - /* entries begin after . and .. */ #define SCOUTFS_DIRENT_FIRST_POS 2 /* getdents returns next pos with an entry, no entry at (f_pos)~0 */ @@ -404,6 +395,18 @@ enum { #define SCOUTFS_MAX_KEY_SIZE \ offsetof(struct scoutfs_link_backref_key, name[SCOUTFS_NAME_LEN + 1]) +/* largest single val are dirents, larger broken up into units of this */ +#define SCOUTFS_MAX_VAL_SIZE \ + offsetof(struct scoutfs_dirent, name[SCOUTFS_NAME_LEN]) + +#define SCOUTFS_XATTR_MAX_NAME_LEN 255 +#define SCOUTFS_XATTR_MAX_SIZE 65536 +#define SCOUTFS_XATTR_PART_SIZE \ + (SCOUTFS_MAX_VAL_SIZE - sizeof(struct scoutfs_xattr_val_header)) +#define SCOUTFS_XATTR_MAX_PARTS \ + DIV_ROUND_UP(SCOUTFS_XATTR_MAX_SIZE, SCOUTFS_XATTR_PART_SIZE) + + /* * messages over the wire. */ diff --git a/kmod/src/item.c b/kmod/src/item.c index 79b18f60..6135b0eb 100644 --- a/kmod/src/item.c +++ b/kmod/src/item.c @@ -41,6 +41,12 @@ * clobber them in creation and skip them in lookups. */ +static bool invalid_key_val(struct scoutfs_key_buf *key, struct kvec *val) +{ + return WARN_ON_ONCE(key->key_len > SCOUTFS_MAX_KEY_SIZE || + (val && (scoutfs_kvec_length(val) > SCOUTFS_MAX_VAL_SIZE))); +} + static bool invalid_flags(int sif) { return (sif & SIF_EXCLUSIVE) && (sif & SIF_REPLACE); @@ -992,6 +998,9 @@ int scoutfs_item_create(struct super_block *sb, struct scoutfs_key_buf *key, unsigned long flags; int ret; + if (invalid_key_val(key, val)) + return -EINVAL; + item = alloc_item(sb, key, val); if (!item) return -ENOMEM; @@ -1021,6 +1030,9 @@ int scoutfs_item_add_batch(struct super_block *sb, struct list_head *list, struct cached_item *item; int ret; + if (invalid_key_val(key, val)) + return -EINVAL; + item = alloc_item(sb, key, val); if (item) { list_add_tail(&item->entry, list); @@ -1128,6 +1140,11 @@ int scoutfs_item_set_batch(struct super_block *sb, struct list_head *list, if (WARN_ON_ONCE(invalid_flags(sif))) return -EINVAL; + list_for_each_entry(item, list, entry) { + if (invalid_key_val(item->key, item->val)) + return -EINVAL; + } + trace_scoutfs_item_set_batch(sb, start, end); if (WARN_ON_ONCE(scoutfs_key_compare(start, end) > 0)) @@ -1283,6 +1300,9 @@ int scoutfs_item_update(struct super_block *sb, struct scoutfs_key_buf *key, unsigned long flags; int ret; + if (invalid_key_val(key, val)) + return -EINVAL; + end = scoutfs_key_alloc(sb, SCOUTFS_MAX_KEY_SIZE); if (!end) { ret = -ENOMEM;