summaryrefslogtreecommitdiff
path: root/libbcachefs
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-05-15 14:43:26 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2021-05-15 14:43:26 -0400
commita76f36fc6e6af7a4ba8d440d84e2cd6b4ec0b88b (patch)
tree04142cb4572bf9f25ef894971857e2a64b03df3f /libbcachefs
parentbf145974607928c32c14d27c5c57e1220cad195d (diff)
Update bcachefs sources to ae6f512de8 bcachefs: Fix out of bounds read in fs usage ioctl
Diffstat (limited to 'libbcachefs')
-rw-r--r--libbcachefs/btree_gc.c4
-rw-r--r--libbcachefs/chardev.c5
-rw-r--r--libbcachefs/fs.c4
-rw-r--r--libbcachefs/fsck.c31
-rw-r--r--libbcachefs/opts.c27
-rw-r--r--libbcachefs/super.c2
6 files changed, 55 insertions, 18 deletions
diff --git a/libbcachefs/btree_gc.c b/libbcachefs/btree_gc.c
index ec6eb106..b0262499 100644
--- a/libbcachefs/btree_gc.c
+++ b/libbcachefs/btree_gc.c
@@ -436,7 +436,7 @@ static int bch2_check_fix_ptrs(struct bch_fs *c, enum btree_id btree_id,
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
bch2_data_types[ptr_data_type(k->k, &p.ptr)],
p.ptr.gen)) {
- if (p.ptr.cached) {
+ if (!p.ptr.cached) {
g2->_mark.gen = g->_mark.gen = p.ptr.gen;
g2->gen_valid = g->gen_valid = true;
set_bit(BCH_FS_NEED_ALLOC_WRITE, &c->flags);
@@ -450,7 +450,7 @@ static int bch2_check_fix_ptrs(struct bch_fs *c, enum btree_id btree_id,
p.ptr.dev, PTR_BUCKET_NR(ca, &p.ptr),
bch2_data_types[ptr_data_type(k->k, &p.ptr)],
p.ptr.gen, g->mark.gen)) {
- if (p.ptr.cached) {
+ if (!p.ptr.cached) {
g2->_mark.gen = g->_mark.gen = p.ptr.gen;
g2->gen_valid = g->gen_valid = true;
g2->_mark.data_type = 0;
diff --git a/libbcachefs/chardev.c b/libbcachefs/chardev.c
index c6160147..c29f8272 100644
--- a/libbcachefs/chardev.c
+++ b/libbcachefs/chardev.c
@@ -414,7 +414,8 @@ static long bch2_ioctl_fs_usage(struct bch_fs *c,
struct bch_replicas_entry *src_e =
cpu_replicas_entry(&c->replicas, i);
- if (replicas_usage_next(dst_e) > dst_end) {
+ /* check that we have enough space for one replicas entry */
+ if (dst_e + 1 > dst_end) {
ret = -ERANGE;
break;
}
@@ -523,7 +524,7 @@ static long bch2_ioctl_read_super(struct bch_fs *c,
ret = copy_to_user((void __user *)(unsigned long)arg.sb,
sb, vstruct_bytes(sb));
err:
- if (ca)
+ if (!IS_ERR_OR_NULL(ca))
percpu_ref_put(&ca->ref);
mutex_unlock(&c->sb_lock);
return ret;
diff --git a/libbcachefs/fs.c b/libbcachefs/fs.c
index b1bbec3f..4c6568e0 100644
--- a/libbcachefs/fs.c
+++ b/libbcachefs/fs.c
@@ -30,6 +30,7 @@
#include <linux/posix_acl.h>
#include <linux/random.h>
#include <linux/statfs.h>
+#include <linux/string.h>
#include <linux/xattr.h>
static struct kmem_cache *bch2_inode_cache;
@@ -1311,6 +1312,9 @@ static char **split_devs(const char *_dev_name, unsigned *nr)
char *dev_name = NULL, **devs = NULL, *s;
size_t i, nr_devs = 0;
+ if (strlen(_dev_name) == 0)
+ return NULL;
+
dev_name = kstrdup(_dev_name, GFP_KERNEL);
if (!dev_name)
return NULL;
diff --git a/libbcachefs/fsck.c b/libbcachefs/fsck.c
index 338d50be..d2697864 100644
--- a/libbcachefs/fsck.c
+++ b/libbcachefs/fsck.c
@@ -512,7 +512,9 @@ static int check_inodes(struct bch_fs *c, bool full)
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
- for_each_btree_key(&trans, iter, BTREE_ID_inodes, POS_MIN, 0, k, ret) {
+ for_each_btree_key(&trans, iter, BTREE_ID_inodes, POS_MIN,
+ BTREE_ITER_INTENT|
+ BTREE_ITER_PREFETCH, k, ret) {
if (k.k->type != KEY_TYPE_inode)
continue;
@@ -621,7 +623,8 @@ static int check_extents(struct bch_fs *c)
iter = bch2_trans_get_iter(&trans, BTREE_ID_extents,
POS(BCACHEFS_ROOT_INO, 0),
- BTREE_ITER_INTENT);
+ BTREE_ITER_INTENT|
+ BTREE_ITER_PREFETCH);
retry:
while ((k = bch2_btree_iter_peek(iter)).k &&
!(ret = bkey_err(k))) {
@@ -719,7 +722,9 @@ static int check_dirents(struct bch_fs *c)
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
iter = bch2_trans_get_iter(&trans, BTREE_ID_dirents,
- POS(BCACHEFS_ROOT_INO, 0), 0);
+ POS(BCACHEFS_ROOT_INO, 0),
+ BTREE_ITER_INTENT|
+ BTREE_ITER_PREFETCH);
retry:
while ((k = bch2_btree_iter_peek(iter)).k &&
!(ret = bkey_err(k))) {
@@ -920,7 +925,9 @@ static int check_xattrs(struct bch_fs *c)
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
iter = bch2_trans_get_iter(&trans, BTREE_ID_xattrs,
- POS(BCACHEFS_ROOT_INO, 0), 0);
+ POS(BCACHEFS_ROOT_INO, 0),
+ BTREE_ITER_INTENT|
+ BTREE_ITER_PREFETCH);
retry:
while ((k = bch2_btree_iter_peek(iter)).k &&
!(ret = bkey_err(k))) {
@@ -1108,7 +1115,9 @@ static int check_directory_structure(struct bch_fs *c)
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
- for_each_btree_key(&trans, iter, BTREE_ID_inodes, POS_MIN, 0, k, ret) {
+ for_each_btree_key(&trans, iter, BTREE_ID_inodes, POS_MIN,
+ BTREE_ITER_INTENT|
+ BTREE_ITER_PREFETCH, k, ret) {
if (k.k->type != KEY_TYPE_inode)
continue;
@@ -1207,7 +1216,9 @@ static int check_nlinks_find_hardlinks(struct bch_fs *c,
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
for_each_btree_key(&trans, iter, BTREE_ID_inodes,
- POS(0, start), 0, k, ret) {
+ POS(0, start),
+ BTREE_ITER_INTENT|
+ BTREE_ITER_PREFETCH, k, ret) {
if (k.k->type != KEY_TYPE_inode)
continue;
@@ -1255,7 +1266,9 @@ static int check_nlinks_walk_dirents(struct bch_fs *c, struct nlink_table *links
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
- for_each_btree_key(&trans, iter, BTREE_ID_dirents, POS_MIN, 0, k, ret) {
+ for_each_btree_key(&trans, iter, BTREE_ID_dirents, POS_MIN,
+ BTREE_ITER_INTENT|
+ BTREE_ITER_PREFETCH, k, ret) {
switch (k.k->type) {
case KEY_TYPE_dirent:
d = bkey_s_c_to_dirent(k);
@@ -1293,7 +1306,9 @@ static int check_nlinks_update_hardlinks(struct bch_fs *c,
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
for_each_btree_key(&trans, iter, BTREE_ID_inodes,
- POS(0, range_start), 0, k, ret) {
+ POS(0, range_start),
+ BTREE_ITER_INTENT|
+ BTREE_ITER_PREFETCH, k, ret) {
if (k.k->p.offset >= range_end)
break;
diff --git a/libbcachefs/opts.c b/libbcachefs/opts.c
index 0cfbb56a..64bf5a38 100644
--- a/libbcachefs/opts.c
+++ b/libbcachefs/opts.c
@@ -315,11 +315,20 @@ int bch2_opts_check_may_set(struct bch_fs *c)
int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
char *options)
{
+ char *copied_opts, *copied_opts_start;
char *opt, *name, *val;
int ret, id;
u64 v;
- while ((opt = strsep(&options, ",")) != NULL) {
+ if (!options)
+ return 0;
+
+ copied_opts = kstrdup(options, GFP_KERNEL);
+ if (!copied_opts)
+ return -1;
+ copied_opts_start = copied_opts;
+
+ while ((opt = strsep(&copied_opts, ",")) != NULL) {
name = strsep(&opt, "=");
val = opt;
@@ -363,16 +372,24 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
bch2_opt_set_by_id(opts, id, v);
}
- return 0;
+ ret = 0;
+ goto out;
+
bad_opt:
pr_err("Bad mount option %s", name);
- return -1;
+ ret = -1;
+ goto out;
bad_val:
pr_err("Invalid value %s for mount option %s", val, name);
- return -1;
+ ret = -1;
+ goto out;
no_val:
pr_err("Mount option %s requires a value", name);
- return -1;
+ ret = -1;
+ goto out;
+out:
+ kfree(copied_opts_start);
+ return ret;
}
/* io opts: */
diff --git a/libbcachefs/super.c b/libbcachefs/super.c
index e5936041..3b1e9203 100644
--- a/libbcachefs/super.c
+++ b/libbcachefs/super.c
@@ -110,7 +110,7 @@ struct bch_fs *bch2_dev_to_fs(dev_t dev)
list_for_each_entry(c, &bch_fs_list, list)
for_each_member_device_rcu(ca, c, i, NULL)
- if (ca->disk_sb.bdev->bd_dev == dev) {
+ if (ca->disk_sb.bdev && ca->disk_sb.bdev->bd_dev == dev) {
closure_get(&c->cl);
goto found;
}