hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/drivers/infiniband/core/uverbs_ioctl.c
....@@ -57,6 +57,8 @@
5757 struct ib_uverbs_attr *uattrs;
5858
5959 DECLARE_BITMAP(uobj_finalize, UVERBS_API_ATTR_BKEY_LEN);
60
+ DECLARE_BITMAP(spec_finalize, UVERBS_API_ATTR_BKEY_LEN);
61
+ DECLARE_BITMAP(uobj_hw_obj_valid, UVERBS_API_ATTR_BKEY_LEN);
6062
6163 /*
6264 * Must be last. bundle ends in a flex array which overlaps
....@@ -135,12 +137,102 @@
135137 static bool uverbs_is_attr_cleared(const struct ib_uverbs_attr *uattr,
136138 u16 len)
137139 {
138
- if (uattr->len > sizeof(((struct ib_uverbs_attr *)0)->data))
140
+ if (uattr->len > sizeof_field(struct ib_uverbs_attr, data))
139141 return ib_is_buffer_cleared(u64_to_user_ptr(uattr->data) + len,
140142 uattr->len - len);
141143
142144 return !memchr_inv((const void *)&uattr->data + len,
143145 0, uattr->len - len);
146
+}
147
+
148
+static int uverbs_set_output(const struct uverbs_attr_bundle *bundle,
149
+ const struct uverbs_attr *attr)
150
+{
151
+ struct bundle_priv *pbundle =
152
+ container_of(bundle, struct bundle_priv, bundle);
153
+ u16 flags;
154
+
155
+ flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
156
+ UVERBS_ATTR_F_VALID_OUTPUT;
157
+ if (put_user(flags,
158
+ &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
159
+ return -EFAULT;
160
+ return 0;
161
+}
162
+
163
+static int uverbs_process_idrs_array(struct bundle_priv *pbundle,
164
+ const struct uverbs_api_attr *attr_uapi,
165
+ struct uverbs_objs_arr_attr *attr,
166
+ struct ib_uverbs_attr *uattr,
167
+ u32 attr_bkey)
168
+{
169
+ const struct uverbs_attr_spec *spec = &attr_uapi->spec;
170
+ size_t array_len;
171
+ u32 *idr_vals;
172
+ int ret = 0;
173
+ size_t i;
174
+
175
+ if (uattr->attr_data.reserved)
176
+ return -EINVAL;
177
+
178
+ if (uattr->len % sizeof(u32))
179
+ return -EINVAL;
180
+
181
+ array_len = uattr->len / sizeof(u32);
182
+ if (array_len < spec->u2.objs_arr.min_len ||
183
+ array_len > spec->u2.objs_arr.max_len)
184
+ return -EINVAL;
185
+
186
+ attr->uobjects =
187
+ uverbs_alloc(&pbundle->bundle,
188
+ array_size(array_len, sizeof(*attr->uobjects)));
189
+ if (IS_ERR(attr->uobjects))
190
+ return PTR_ERR(attr->uobjects);
191
+
192
+ /*
193
+ * Since idr is 4B and *uobjects is >= 4B, we can use attr->uobjects
194
+ * to store idrs array and avoid additional memory allocation. The
195
+ * idrs array is offset to the end of the uobjects array so we will be
196
+ * able to read idr and replace with a pointer.
197
+ */
198
+ idr_vals = (u32 *)(attr->uobjects + array_len) - array_len;
199
+
200
+ if (uattr->len > sizeof(uattr->data)) {
201
+ ret = copy_from_user(idr_vals, u64_to_user_ptr(uattr->data),
202
+ uattr->len);
203
+ if (ret)
204
+ return -EFAULT;
205
+ } else {
206
+ memcpy(idr_vals, &uattr->data, uattr->len);
207
+ }
208
+
209
+ for (i = 0; i != array_len; i++) {
210
+ attr->uobjects[i] = uverbs_get_uobject_from_file(
211
+ spec->u2.objs_arr.obj_type, spec->u2.objs_arr.access,
212
+ idr_vals[i], &pbundle->bundle);
213
+ if (IS_ERR(attr->uobjects[i])) {
214
+ ret = PTR_ERR(attr->uobjects[i]);
215
+ break;
216
+ }
217
+ }
218
+
219
+ attr->len = i;
220
+ __set_bit(attr_bkey, pbundle->spec_finalize);
221
+ return ret;
222
+}
223
+
224
+static void uverbs_free_idrs_array(const struct uverbs_api_attr *attr_uapi,
225
+ struct uverbs_objs_arr_attr *attr,
226
+ bool commit,
227
+ struct uverbs_attr_bundle *attrs)
228
+{
229
+ const struct uverbs_attr_spec *spec = &attr_uapi->spec;
230
+ size_t i;
231
+
232
+ for (i = 0; i != attr->len; i++)
233
+ uverbs_finalize_object(attr->uobjects[i],
234
+ spec->u2.objs_arr.access, false, commit,
235
+ attrs);
144236 }
145237
146238 static int uverbs_process_attr(struct bundle_priv *pbundle,
....@@ -167,7 +259,7 @@
167259 return -EOPNOTSUPP;
168260
169261 e->ptr_attr.enum_id = uattr->attr_data.enum_data.elem_id;
170
- /* fall through */
262
+ fallthrough;
171263 case UVERBS_ATTR_TYPE_PTR_IN:
172264 /* Ensure that any data provided by userspace beyond the known
173265 * struct is zero. Userspace that knows how to use some future
....@@ -179,7 +271,7 @@
179271 !uverbs_is_attr_cleared(uattr, val_spec->u.ptr.len))
180272 return -EOPNOTSUPP;
181273
182
- /* fall through */
274
+ fallthrough;
183275 case UVERBS_ATTR_TYPE_PTR_OUT:
184276 if (uattr->len < val_spec->u.ptr.min_len ||
185277 (!val_spec->zero_trailing &&
....@@ -228,10 +320,8 @@
228320 * IDR implementation today rejects negative IDs
229321 */
230322 o_attr->uobject = uverbs_get_uobject_from_file(
231
- spec->u.obj.obj_type,
232
- pbundle->bundle.ufile,
233
- spec->u.obj.access,
234
- uattr->data_s64);
323
+ spec->u.obj.obj_type, spec->u.obj.access,
324
+ uattr->data_s64, &pbundle->bundle);
235325 if (IS_ERR(o_attr->uobject))
236326 return PTR_ERR(o_attr->uobject);
237327 __set_bit(attr_bkey, pbundle->uobj_finalize);
....@@ -246,6 +336,11 @@
246336 }
247337
248338 break;
339
+
340
+ case UVERBS_ATTR_TYPE_IDRS_ARRAY:
341
+ return uverbs_process_idrs_array(pbundle, attr_uapi,
342
+ &e->objs_arr_attr, uattr,
343
+ attr_bkey);
249344 default:
250345 return -EOPNOTSUPP;
251346 }
....@@ -300,8 +395,7 @@
300395 return -EPROTONOSUPPORT;
301396 return 0;
302397 }
303
- attr = srcu_dereference(
304
- *slot, &pbundle->bundle.ufile->device->disassociate_srcu);
398
+ attr = rcu_dereference_protected(*slot, true);
305399
306400 /* Reject duplicate attributes from user-space */
307401 if (test_bit(attr_bkey, pbundle->bundle.attr_present))
....@@ -319,8 +413,7 @@
319413 static int ib_uverbs_run_method(struct bundle_priv *pbundle,
320414 unsigned int num_attrs)
321415 {
322
- int (*handler)(struct ib_uverbs_file *ufile,
323
- struct uverbs_attr_bundle *ctx);
416
+ int (*handler)(struct uverbs_attr_bundle *attrs);
324417 size_t uattrs_size = array_size(sizeof(*pbundle->uattrs), num_attrs);
325418 unsigned int destroy_bkey = pbundle->method_elm->destroy_bkey;
326419 unsigned int i;
....@@ -351,19 +444,39 @@
351444 pbundle->method_elm->key_bitmap_len)))
352445 return -EINVAL;
353446
447
+ if (pbundle->method_elm->has_udata)
448
+ uverbs_fill_udata(&pbundle->bundle,
449
+ &pbundle->bundle.driver_udata,
450
+ UVERBS_ATTR_UHW_IN, UVERBS_ATTR_UHW_OUT);
451
+ else
452
+ pbundle->bundle.driver_udata = (struct ib_udata){};
453
+
354454 if (destroy_bkey != UVERBS_API_ATTR_BKEY_LEN) {
355455 struct uverbs_obj_attr *destroy_attr =
356456 &pbundle->bundle.attrs[destroy_bkey].obj_attr;
357457
358
- ret = uobj_destroy(destroy_attr->uobject);
458
+ ret = uobj_destroy(destroy_attr->uobject, &pbundle->bundle);
359459 if (ret)
360460 return ret;
361461 __clear_bit(destroy_bkey, pbundle->uobj_finalize);
362462
363
- ret = handler(pbundle->bundle.ufile, &pbundle->bundle);
463
+ ret = handler(&pbundle->bundle);
364464 uobj_put_destroy(destroy_attr->uobject);
365465 } else {
366
- ret = handler(pbundle->bundle.ufile, &pbundle->bundle);
466
+ ret = handler(&pbundle->bundle);
467
+ }
468
+
469
+ /*
470
+ * Until the drivers are revised to use the bundle directly we have to
471
+ * assume that the driver wrote to its UHW_OUT and flag userspace
472
+ * appropriately.
473
+ */
474
+ if (!ret && pbundle->method_elm->has_udata) {
475
+ const struct uverbs_attr *attr =
476
+ uverbs_attr_get(&pbundle->bundle, UVERBS_ATTR_UHW_OUT);
477
+
478
+ if (!IS_ERR(attr))
479
+ ret = uverbs_set_output(&pbundle->bundle, attr);
367480 }
368481
369482 /*
....@@ -377,24 +490,45 @@
377490 return ret;
378491 }
379492
380
-static int bundle_destroy(struct bundle_priv *pbundle, bool commit)
493
+static void bundle_destroy(struct bundle_priv *pbundle, bool commit)
381494 {
382495 unsigned int key_bitmap_len = pbundle->method_elm->key_bitmap_len;
383496 struct bundle_alloc_head *memblock;
384497 unsigned int i;
385
- int ret = 0;
386498
499
+ /* fast path for simple uobjects */
387500 i = -1;
388501 while ((i = find_next_bit(pbundle->uobj_finalize, key_bitmap_len,
389502 i + 1)) < key_bitmap_len) {
390503 struct uverbs_attr *attr = &pbundle->bundle.attrs[i];
391
- int current_ret;
392504
393
- current_ret = uverbs_finalize_object(
505
+ uverbs_finalize_object(
394506 attr->obj_attr.uobject,
395
- attr->obj_attr.attr_elm->spec.u.obj.access, commit);
396
- if (!ret)
397
- ret = current_ret;
507
+ attr->obj_attr.attr_elm->spec.u.obj.access,
508
+ test_bit(i, pbundle->uobj_hw_obj_valid),
509
+ commit,
510
+ &pbundle->bundle);
511
+ }
512
+
513
+ i = -1;
514
+ while ((i = find_next_bit(pbundle->spec_finalize, key_bitmap_len,
515
+ i + 1)) < key_bitmap_len) {
516
+ struct uverbs_attr *attr = &pbundle->bundle.attrs[i];
517
+ const struct uverbs_api_attr *attr_uapi;
518
+ void __rcu **slot;
519
+
520
+ slot = uapi_get_attr_for_method(
521
+ pbundle,
522
+ pbundle->method_key | uapi_bkey_to_key_attr(i));
523
+ if (WARN_ON(!slot))
524
+ continue;
525
+
526
+ attr_uapi = rcu_dereference_protected(*slot, true);
527
+
528
+ if (attr_uapi->spec.type == UVERBS_ATTR_TYPE_IDRS_ARRAY) {
529
+ uverbs_free_idrs_array(attr_uapi, &attr->objs_arr_attr,
530
+ commit, &pbundle->bundle);
531
+ }
398532 }
399533
400534 for (memblock = pbundle->allocated_mem; memblock;) {
....@@ -403,8 +537,6 @@
403537 memblock = memblock->next;
404538 kvfree(tmp);
405539 }
406
-
407
- return ret;
408540 }
409541
410542 static int ib_uverbs_cmd_verbs(struct ib_uverbs_file *ufile,
....@@ -417,7 +549,6 @@
417549 struct bundle_priv *pbundle;
418550 struct bundle_priv onstack;
419551 void __rcu **slot;
420
- int destroy_ret;
421552 int ret;
422553
423554 if (unlikely(hdr->driver_id != uapi->driver_id))
....@@ -429,7 +560,7 @@
429560 uapi_key_ioctl_method(hdr->method_id));
430561 if (unlikely(!slot))
431562 return -EPROTONOSUPPORT;
432
- method_elm = srcu_dereference(*slot, &ufile->device->disassociate_srcu);
563
+ method_elm = rcu_dereference_protected(*slot, true);
433564
434565 if (!method_elm->use_stack) {
435566 pbundle = kmalloc(method_elm->bundle_size, GFP_KERNEL);
....@@ -450,6 +581,7 @@
450581 pbundle->method_elm = method_elm;
451582 pbundle->method_key = attrs_iter.index;
452583 pbundle->bundle.ufile = ufile;
584
+ pbundle->bundle.context = NULL; /* only valid if bundle has uobject */
453585 pbundle->radix = &uapi->radix;
454586 pbundle->radix_slots = slot;
455587 pbundle->radix_slots_len = radix_tree_chunk_size(&attrs_iter);
....@@ -461,12 +593,12 @@
461593 memset(pbundle->bundle.attr_present, 0,
462594 sizeof(pbundle->bundle.attr_present));
463595 memset(pbundle->uobj_finalize, 0, sizeof(pbundle->uobj_finalize));
596
+ memset(pbundle->spec_finalize, 0, sizeof(pbundle->spec_finalize));
597
+ memset(pbundle->uobj_hw_obj_valid, 0,
598
+ sizeof(pbundle->uobj_hw_obj_valid));
464599
465600 ret = ib_uverbs_run_method(pbundle, hdr->num_attrs);
466
- destroy_ret = bundle_destroy(pbundle, ret == 0);
467
- if (unlikely(destroy_ret && !ret))
468
- return destroy_ret;
469
-
601
+ bundle_destroy(pbundle, ret == 0);
470602 return ret;
471603 }
472604
....@@ -551,35 +683,37 @@
551683 EXPORT_SYMBOL(uverbs_get_flags32);
552684
553685 /*
554
- * This is for ease of conversion. The purpose is to convert all drivers to
555
- * use uverbs_attr_bundle instead of ib_udata. Assume attr == 0 is input and
556
- * attr == 1 is output.
686
+ * Fill a ib_udata struct (core or uhw) using the given attribute IDs.
687
+ * This is primarily used to convert the UVERBS_ATTR_UHW() into the
688
+ * ib_udata format used by the drivers.
557689 */
558
-void create_udata(struct uverbs_attr_bundle *bundle, struct ib_udata *udata)
690
+void uverbs_fill_udata(struct uverbs_attr_bundle *bundle,
691
+ struct ib_udata *udata, unsigned int attr_in,
692
+ unsigned int attr_out)
559693 {
560694 struct bundle_priv *pbundle =
561695 container_of(bundle, struct bundle_priv, bundle);
562
- const struct uverbs_attr *uhw_in =
563
- uverbs_attr_get(bundle, UVERBS_ATTR_UHW_IN);
564
- const struct uverbs_attr *uhw_out =
565
- uverbs_attr_get(bundle, UVERBS_ATTR_UHW_OUT);
696
+ const struct uverbs_attr *in =
697
+ uverbs_attr_get(&pbundle->bundle, attr_in);
698
+ const struct uverbs_attr *out =
699
+ uverbs_attr_get(&pbundle->bundle, attr_out);
566700
567
- if (!IS_ERR(uhw_in)) {
568
- udata->inlen = uhw_in->ptr_attr.len;
569
- if (uverbs_attr_ptr_is_inline(uhw_in))
701
+ if (!IS_ERR(in)) {
702
+ udata->inlen = in->ptr_attr.len;
703
+ if (uverbs_attr_ptr_is_inline(in))
570704 udata->inbuf =
571
- &pbundle->user_attrs[uhw_in->ptr_attr.uattr_idx]
705
+ &pbundle->user_attrs[in->ptr_attr.uattr_idx]
572706 .data;
573707 else
574
- udata->inbuf = u64_to_user_ptr(uhw_in->ptr_attr.data);
708
+ udata->inbuf = u64_to_user_ptr(in->ptr_attr.data);
575709 } else {
576710 udata->inbuf = NULL;
577711 udata->inlen = 0;
578712 }
579713
580
- if (!IS_ERR(uhw_out)) {
581
- udata->outbuf = u64_to_user_ptr(uhw_out->ptr_attr.data);
582
- udata->outlen = uhw_out->ptr_attr.len;
714
+ if (!IS_ERR(out)) {
715
+ udata->outbuf = u64_to_user_ptr(out->ptr_attr.data);
716
+ udata->outlen = out->ptr_attr.len;
583717 } else {
584718 udata->outbuf = NULL;
585719 udata->outlen = 0;
....@@ -589,10 +723,7 @@
589723 int uverbs_copy_to(const struct uverbs_attr_bundle *bundle, size_t idx,
590724 const void *from, size_t size)
591725 {
592
- struct bundle_priv *pbundle =
593
- container_of(bundle, struct bundle_priv, bundle);
594726 const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
595
- u16 flags;
596727 size_t min_size;
597728
598729 if (IS_ERR(attr))
....@@ -602,12 +733,73 @@
602733 if (copy_to_user(u64_to_user_ptr(attr->ptr_attr.data), from, min_size))
603734 return -EFAULT;
604735
605
- flags = pbundle->uattrs[attr->ptr_attr.uattr_idx].flags |
606
- UVERBS_ATTR_F_VALID_OUTPUT;
607
- if (put_user(flags,
608
- &pbundle->user_attrs[attr->ptr_attr.uattr_idx].flags))
609
- return -EFAULT;
736
+ return uverbs_set_output(bundle, attr);
737
+}
738
+EXPORT_SYMBOL(uverbs_copy_to);
739
+
740
+
741
+/*
742
+ * This is only used if the caller has directly used copy_to_use to write the
743
+ * data. It signals to user space that the buffer is filled in.
744
+ */
745
+int uverbs_output_written(const struct uverbs_attr_bundle *bundle, size_t idx)
746
+{
747
+ const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
748
+
749
+ if (IS_ERR(attr))
750
+ return PTR_ERR(attr);
751
+
752
+ return uverbs_set_output(bundle, attr);
753
+}
754
+
755
+int _uverbs_get_const(s64 *to, const struct uverbs_attr_bundle *attrs_bundle,
756
+ size_t idx, s64 lower_bound, u64 upper_bound,
757
+ s64 *def_val)
758
+{
759
+ const struct uverbs_attr *attr;
760
+
761
+ attr = uverbs_attr_get(attrs_bundle, idx);
762
+ if (IS_ERR(attr)) {
763
+ if ((PTR_ERR(attr) != -ENOENT) || !def_val)
764
+ return PTR_ERR(attr);
765
+
766
+ *to = *def_val;
767
+ } else {
768
+ *to = attr->ptr_attr.data;
769
+ }
770
+
771
+ if (*to < lower_bound || (*to > 0 && (u64)*to > upper_bound))
772
+ return -EINVAL;
610773
611774 return 0;
612775 }
613
-EXPORT_SYMBOL(uverbs_copy_to);
776
+EXPORT_SYMBOL(_uverbs_get_const);
777
+
778
+int uverbs_copy_to_struct_or_zero(const struct uverbs_attr_bundle *bundle,
779
+ size_t idx, const void *from, size_t size)
780
+{
781
+ const struct uverbs_attr *attr = uverbs_attr_get(bundle, idx);
782
+
783
+ if (IS_ERR(attr))
784
+ return PTR_ERR(attr);
785
+
786
+ if (size < attr->ptr_attr.len) {
787
+ if (clear_user(u64_to_user_ptr(attr->ptr_attr.data) + size,
788
+ attr->ptr_attr.len - size))
789
+ return -EFAULT;
790
+ }
791
+ return uverbs_copy_to(bundle, idx, from, size);
792
+}
793
+EXPORT_SYMBOL(uverbs_copy_to_struct_or_zero);
794
+
795
+/* Once called an abort will call through to the type's destroy_hw() */
796
+void uverbs_finalize_uobj_create(const struct uverbs_attr_bundle *bundle,
797
+ u16 idx)
798
+{
799
+ struct bundle_priv *pbundle =
800
+ container_of(bundle, struct bundle_priv, bundle);
801
+
802
+ __set_bit(uapi_bkey_attr(uapi_key_attr(idx)),
803
+ pbundle->uobj_hw_obj_valid);
804
+}
805
+EXPORT_SYMBOL(uverbs_finalize_uobj_create);