Skip to content

Commit 374b3d3

Browse files
author
Kent Overstreet
committed
bcachefs: Fix BCH_IOCTL_FSCK_OFFLINE for encrypted filesystems
To open an encrypted filesystem, we use request_key() to get the encryption key from the user's keyring - but request_key() needs to happen in the context of the process that invoked the ioctl. This easily fixed by using bch2_fs_open() in nostart mode. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
1 parent cf979fc commit 374b3d3

1 file changed

Lines changed: 50 additions & 44 deletions

File tree

fs/bcachefs/chardev.c

Lines changed: 50 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -134,42 +134,38 @@ static long bch2_ioctl_incremental(struct bch_ioctl_incremental __user *user_arg
134134
struct fsck_thread {
135135
struct thread_with_stdio thr;
136136
struct bch_fs *c;
137-
char **devs;
138-
size_t nr_devs;
139137
struct bch_opts opts;
140138
};
141139

142140
static void bch2_fsck_thread_exit(struct thread_with_stdio *_thr)
143141
{
144142
struct fsck_thread *thr = container_of(_thr, struct fsck_thread, thr);
145-
if (thr->devs)
146-
for (size_t i = 0; i < thr->nr_devs; i++)
147-
kfree(thr->devs[i]);
148-
kfree(thr->devs);
149143
kfree(thr);
150144
}
151145

152146
static int bch2_fsck_offline_thread_fn(struct thread_with_stdio *stdio)
153147
{
154148
struct fsck_thread *thr = container_of(stdio, struct fsck_thread, thr);
155-
struct bch_fs *c = bch2_fs_open(thr->devs, thr->nr_devs, thr->opts);
156-
157-
if (IS_ERR(c))
158-
return PTR_ERR(c);
149+
struct bch_fs *c = thr->c;
159150

160-
int ret = 0;
161-
if (test_bit(BCH_FS_errors_fixed, &c->flags))
162-
ret |= 1;
163-
if (test_bit(BCH_FS_error, &c->flags))
164-
ret |= 4;
151+
int ret = PTR_ERR_OR_ZERO(c);
152+
if (ret)
153+
return ret;
165154

166-
bch2_fs_stop(c);
155+
ret = bch2_fs_start(thr->c);
156+
if (ret)
157+
goto err;
167158

168-
if (ret & 1)
159+
if (test_bit(BCH_FS_errors_fixed, &c->flags)) {
169160
bch2_stdio_redirect_printf(&stdio->stdio, false, "%s: errors fixed\n", c->name);
170-
if (ret & 4)
161+
ret |= 1;
162+
}
163+
if (test_bit(BCH_FS_error, &c->flags)) {
171164
bch2_stdio_redirect_printf(&stdio->stdio, false, "%s: still has errors\n", c->name);
172-
165+
ret |= 4;
166+
}
167+
err:
168+
bch2_fs_stop(c);
173169
return ret;
174170
}
175171

@@ -182,7 +178,7 @@ static long bch2_ioctl_fsck_offline(struct bch_ioctl_fsck_offline __user *user_a
182178
{
183179
struct bch_ioctl_fsck_offline arg;
184180
struct fsck_thread *thr = NULL;
185-
u64 *devs = NULL;
181+
darray_str(devs) = {};
186182
long ret = 0;
187183

188184
if (copy_from_user(&arg, user_arg, sizeof(arg)))
@@ -194,29 +190,32 @@ static long bch2_ioctl_fsck_offline(struct bch_ioctl_fsck_offline __user *user_a
194190
if (!capable(CAP_SYS_ADMIN))
195191
return -EPERM;
196192

197-
if (!(devs = kcalloc(arg.nr_devs, sizeof(*devs), GFP_KERNEL)) ||
198-
!(thr = kzalloc(sizeof(*thr), GFP_KERNEL)) ||
199-
!(thr->devs = kcalloc(arg.nr_devs, sizeof(*thr->devs), GFP_KERNEL))) {
200-
ret = -ENOMEM;
201-
goto err;
202-
}
193+
for (size_t i = 0; i < arg.nr_devs; i++) {
194+
u64 dev_u64;
195+
ret = copy_from_user_errcode(&dev_u64, &user_arg->devs[i], sizeof(u64));
196+
if (ret)
197+
goto err;
203198

204-
thr->opts = bch2_opts_empty();
205-
thr->nr_devs = arg.nr_devs;
199+
char *dev_str = strndup_user((char __user *)(unsigned long) dev_u64, PATH_MAX);
200+
ret = PTR_ERR_OR_ZERO(dev_str);
201+
if (ret)
202+
goto err;
206203

207-
if (copy_from_user(devs, &user_arg->devs[0],
208-
array_size(sizeof(user_arg->devs[0]), arg.nr_devs))) {
209-
ret = -EINVAL;
210-
goto err;
204+
ret = darray_push(&devs, dev_str);
205+
if (ret) {
206+
kfree(dev_str);
207+
goto err;
208+
}
211209
}
212210

213-
for (size_t i = 0; i < arg.nr_devs; i++) {
214-
thr->devs[i] = strndup_user((char __user *)(unsigned long) devs[i], PATH_MAX);
215-
ret = PTR_ERR_OR_ZERO(thr->devs[i]);
216-
if (ret)
217-
goto err;
211+
thr = kzalloc(sizeof(*thr), GFP_KERNEL);
212+
if (!thr) {
213+
ret = -ENOMEM;
214+
goto err;
218215
}
219216

217+
thr->opts = bch2_opts_empty();
218+
220219
if (arg.opts) {
221220
char *optstr = strndup_user((char __user *)(unsigned long) arg.opts, 1 << 16);
222221

@@ -230,15 +229,22 @@ static long bch2_ioctl_fsck_offline(struct bch_ioctl_fsck_offline __user *user_a
230229

231230
opt_set(thr->opts, stdio, (u64)(unsigned long)&thr->thr.stdio);
232231

232+
/* We need request_key() to be called before we punt to kthread: */
233+
opt_set(thr->opts, nostart, true);
234+
235+
thr->c = bch2_fs_open(devs.data, arg.nr_devs, thr->opts);
236+
233237
ret = bch2_run_thread_with_stdio(&thr->thr, &bch2_offline_fsck_ops);
234-
err:
235-
if (ret < 0) {
236-
if (thr)
237-
bch2_fsck_thread_exit(&thr->thr);
238-
pr_err("ret %s", bch2_err_str(ret));
239-
}
240-
kfree(devs);
238+
out:
239+
darray_for_each(devs, i)
240+
kfree(*i);
241+
darray_exit(&devs);
241242
return ret;
243+
err:
244+
if (thr)
245+
bch2_fsck_thread_exit(&thr->thr);
246+
pr_err("ret %s", bch2_err_str(ret));
247+
goto out;
242248
}
243249

244250
static long bch2_global_ioctl(unsigned cmd, void __user *arg)

0 commit comments

Comments
 (0)