Skip to content

Commit ff62b79

Browse files
committed
Merge branch 'ynl-avoid-leaks-in-attr-override-and-spec-fixes-for-c'
Jakub Kicinski says: ==================== ynl: avoid leaks in attr override and spec fixes for C The C rt-link work revealed more problems in existing codegen and classic netlink specs. Patches 1 - 4 fix issues with the codegen. Patches 1 and 2 are pre-requisites for patch 3. Patch 3 fixes leaking memory if user tries to override already set attr. Patch 4 validates attrs in case kernel sends something we don't expect. Remaining patches fix and align the specs. Patch 5 changes nesting, the rest are naming adjustments. ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 00ffb37 + e31f86e commit ff62b79

File tree

3 files changed

+92
-38
lines changed

3 files changed

+92
-38
lines changed

Documentation/netlink/specs/rt_link.yaml

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,11 +1113,10 @@ attribute-sets:
11131113
-
11141114
name: prop-list
11151115
type: nest
1116-
nested-attributes: link-attrs
1116+
nested-attributes: prop-list-link-attrs
11171117
-
11181118
name: alt-ifname
11191119
type: string
1120-
multi-attr: true
11211120
-
11221121
name: perm-address
11231122
type: binary
@@ -1163,6 +1162,13 @@ attribute-sets:
11631162
-
11641163
name: netns-immutable
11651164
type: u8
1165+
-
1166+
name: prop-list-link-attrs
1167+
subset-of: link-attrs
1168+
attributes:
1169+
-
1170+
name: alt-ifname
1171+
multi-attr: true
11661172
-
11671173
name: af-spec-attrs
11681174
attributes:
@@ -1585,7 +1591,7 @@ attribute-sets:
15851591
name: nf-call-iptables
15861592
type: u8
15871593
-
1588-
name: nf-call-ip6-tables
1594+
name: nf-call-ip6tables
15891595
type: u8
15901596
-
15911597
name: nf-call-arptables
@@ -2077,7 +2083,7 @@ attribute-sets:
20772083
name: id
20782084
type: u16
20792085
-
2080-
name: flag
2086+
name: flags
20812087
type: binary
20822088
struct: ifla-vlan-flags
20832089
-
@@ -2165,7 +2171,7 @@ attribute-sets:
21652171
type: binary
21662172
struct: ifla-cacheinfo
21672173
-
2168-
name: icmp6-stats
2174+
name: icmp6stats
21692175
type: binary
21702176
struct: ifla-icmp6-stats
21712177
-
@@ -2179,9 +2185,10 @@ attribute-sets:
21792185
type: u32
21802186
-
21812187
name: mctp-attrs
2188+
name-prefix: ifla-mctp-
21822189
attributes:
21832190
-
2184-
name: mctp-net
2191+
name: net
21852192
type: u32
21862193
-
21872194
name: phys-binding
@@ -2453,7 +2460,6 @@ operations:
24532460
- min-mtu
24542461
- max-mtu
24552462
- prop-list
2456-
- alt-ifname
24572463
- perm-address
24582464
- proto-down-reason
24592465
- parent-dev-name

Documentation/netlink/specs/rt_neigh.yaml

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,25 @@ definitions:
1313
type: struct
1414
members:
1515
-
16-
name: family
16+
name: ndm-family
1717
type: u8
1818
-
19-
name: pad
19+
name: ndm-pad
2020
type: pad
2121
len: 3
2222
-
23-
name: ifindex
23+
name: ndm-ifindex
2424
type: s32
2525
-
26-
name: state
26+
name: ndm-state
2727
type: u16
2828
enum: nud-state
2929
-
30-
name: flags
30+
name: ndm-flags
3131
type: u8
3232
enum: ntf-flags
3333
-
34-
name: type
34+
name: ndm-type
3535
type: u8
3636
enum: rtm-type
3737
-
@@ -189,7 +189,7 @@ attribute-sets:
189189
type: binary
190190
display-hint: ipv4
191191
-
192-
name: lladr
192+
name: lladdr
193193
type: binary
194194
display-hint: mac
195195
-

tools/net/ynl/pyynl/ynl_gen_c.py

Lines changed: 72 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,15 @@ def _complex_member_type(self, ri):
162162
def free_needs_iter(self):
163163
return False
164164

165-
def free(self, ri, var, ref):
165+
def _free_lines(self, ri, var, ref):
166166
if self.is_multi_val() or self.presence_type() == 'len':
167-
ri.cw.p(f'free({var}->{ref}{self.c_name});')
167+
return [f'free({var}->{ref}{self.c_name});']
168+
return []
169+
170+
def free(self, ri, var, ref):
171+
lines = self._free_lines(ri, var, ref)
172+
for line in lines:
173+
ri.cw.p(line)
168174

169175
def arg_member(self, ri):
170176
member = self._complex_member_type(ri)
@@ -263,6 +269,10 @@ def setter(self, ri, space, direction, deref=False, ref=None):
263269
var = "req"
264270
member = f"{var}->{'.'.join(ref)}"
265271

272+
local_vars = []
273+
if self.free_needs_iter():
274+
local_vars += ['unsigned int i;']
275+
266276
code = []
267277
presence = ''
268278
for i in range(0, len(ref)):
@@ -272,14 +282,19 @@ def setter(self, ri, space, direction, deref=False, ref=None):
272282
if i == len(ref) - 1 and self.presence_type() != 'bit':
273283
continue
274284
code.append(presence + ' = 1;')
285+
ref_path = '.'.join(ref[:-1])
286+
if ref_path:
287+
ref_path += '.'
288+
code += self._free_lines(ri, var, ref_path)
275289
code += self._setter_lines(ri, member, presence)
276290

277291
func_name = f"{op_prefix(ri, direction, deref=deref)}_set_{'_'.join(ref)}"
278292
free = bool([x for x in code if 'free(' in x])
279293
alloc = bool([x for x in code if 'alloc(' in x])
280294
if free and not alloc:
281295
func_name = '__' + func_name
282-
ri.cw.write_func('static inline void', func_name, body=code,
296+
ri.cw.write_func('static inline void', func_name, local_vars=local_vars,
297+
body=code,
283298
args=[f'{type_name(ri, direction, deref=deref)} *{var}'] + self.arg_member(ri))
284299

285300

@@ -482,8 +497,7 @@ def _attr_get(self, ri, var):
482497
['unsigned int len;']
483498

484499
def _setter_lines(self, ri, member, presence):
485-
return [f"free({member});",
486-
f"{presence}_len = strlen({self.c_name});",
500+
return [f"{presence}_len = strlen({self.c_name});",
487501
f"{member} = malloc({presence}_len + 1);",
488502
f'memcpy({member}, {self.c_name}, {presence}_len);',
489503
f'{member}[{presence}_len] = 0;']
@@ -536,8 +550,7 @@ def _attr_get(self, ri, var):
536550
['unsigned int len;']
537551

538552
def _setter_lines(self, ri, member, presence):
539-
return [f"free({member});",
540-
f"{presence}_len = len;",
553+
return [f"{presence}_len = len;",
541554
f"{member} = malloc({presence}_len);",
542555
f'memcpy({member}, {self.c_name}, {presence}_len);']
543556

@@ -574,12 +587,14 @@ def is_recursive(self):
574587
def _complex_member_type(self, ri):
575588
return self.nested_struct_type
576589

577-
def free(self, ri, var, ref):
590+
def _free_lines(self, ri, var, ref):
591+
lines = []
578592
at = '&'
579593
if self.is_recursive_for_op(ri):
580594
at = ''
581-
ri.cw.p(f'if ({var}->{ref}{self.c_name})')
582-
ri.cw.p(f'{self.nested_render_name}_free({at}{var}->{ref}{self.c_name});')
595+
lines += [f'if ({var}->{ref}{self.c_name})']
596+
lines += [f'{self.nested_render_name}_free({at}{var}->{ref}{self.c_name});']
597+
return lines
583598

584599
def _attr_typol(self):
585600
return f'.type = YNL_PT_NEST, .nest = &{self.nested_render_name}_nest, '
@@ -632,15 +647,19 @@ def _complex_member_type(self, ri):
632647
def free_needs_iter(self):
633648
return 'type' not in self.attr or self.attr['type'] == 'nest'
634649

635-
def free(self, ri, var, ref):
650+
def _free_lines(self, ri, var, ref):
651+
lines = []
636652
if self.attr['type'] in scalars:
637-
ri.cw.p(f"free({var}->{ref}{self.c_name});")
653+
lines += [f"free({var}->{ref}{self.c_name});"]
638654
elif 'type' not in self.attr or self.attr['type'] == 'nest':
639-
ri.cw.p(f"for (i = 0; i < {var}->{ref}n_{self.c_name}; i++)")
640-
ri.cw.p(f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);')
641-
ri.cw.p(f"free({var}->{ref}{self.c_name});")
655+
lines += [
656+
f"for (i = 0; i < {var}->{ref}n_{self.c_name}; i++)",
657+
f'{self.nested_render_name}_free(&{var}->{ref}{self.c_name}[i]);',
658+
f"free({var}->{ref}{self.c_name});",
659+
]
642660
else:
643661
raise Exception(f"Free of MultiAttr sub-type {self.attr['type']} not supported yet")
662+
return lines
644663

645664
def _attr_policy(self, policy):
646665
return self.base_type._attr_policy(policy)
@@ -654,10 +673,10 @@ def _attr_get(self, ri, var):
654673
def attr_put(self, ri, var):
655674
if self.attr['type'] in scalars:
656675
put_type = self.type
657-
ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)")
676+
ri.cw.p(f"for (i = 0; i < {var}->n_{self.c_name}; i++)")
658677
ri.cw.p(f"ynl_attr_put_{put_type}(nlh, {self.enum_name}, {var}->{self.c_name}[i]);")
659678
elif 'type' not in self.attr or self.attr['type'] == 'nest':
660-
ri.cw.p(f"for (unsigned int i = 0; i < {var}->n_{self.c_name}; i++)")
679+
ri.cw.p(f"for (i = 0; i < {var}->n_{self.c_name}; i++)")
661680
self._attr_put_line(ri, var, f"{self.nested_render_name}_put(nlh, " +
662681
f"{self.enum_name}, &{var}->{self.c_name}[i])")
663682
else:
@@ -666,8 +685,7 @@ def attr_put(self, ri, var):
666685
def _setter_lines(self, ri, member, presence):
667686
# For multi-attr we have a count, not presence, hack up the presence
668687
presence = presence[:-(len('_present.') + len(self.c_name))] + "n_" + self.c_name
669-
return [f"free({member});",
670-
f"{member} = {self.c_name};",
688+
return [f"{member} = {self.c_name};",
671689
f"{presence} = n_{self.c_name};"]
672690

673691

@@ -696,8 +714,11 @@ def _attr_typol(self):
696714
def _attr_get(self, ri, var):
697715
local_vars = ['const struct nlattr *attr2;']
698716
get_lines = [f'attr_{self.c_name} = attr;',
699-
'ynl_attr_for_each_nested(attr2, attr)',
700-
f'\t{var}->n_{self.c_name}++;']
717+
'ynl_attr_for_each_nested(attr2, attr) {',
718+
'\tif (ynl_attr_validate(yarg, attr2))',
719+
'\t\treturn YNL_PARSE_CB_ERROR;',
720+
f'\t{var}->n_{self.c_name}++;',
721+
'}']
701722
return get_lines, None, local_vars
702723

703724

@@ -755,6 +776,7 @@ def __init__(self, family, space_name, type_list=None, inherited=None):
755776
self.request = False
756777
self.reply = False
757778
self.recursive = False
779+
self.in_multi_val = False # used by a MultiAttr or and legacy arrays
758780

759781
self.attr_list = []
760782
self.attrs = dict()
@@ -1122,6 +1144,10 @@ def _load_nested_sets(self):
11221144
if attr in rs_members['reply']:
11231145
self.pure_nested_structs[nested].reply = True
11241146

1147+
if spec.is_multi_val():
1148+
child = self.pure_nested_structs.get(nested)
1149+
child.in_multi_val = True
1150+
11251151
self._sort_pure_types()
11261152

11271153
# Propagate the request / reply / recursive
@@ -1136,6 +1162,8 @@ def _load_nested_sets(self):
11361162
struct.child_nests.update(child.child_nests)
11371163
child.request |= struct.request
11381164
child.reply |= struct.reply
1165+
if spec.is_multi_val():
1166+
child.in_multi_val = True
11391167
if attr_set in struct.child_nests:
11401168
struct.recursive = True
11411169

@@ -1399,9 +1427,9 @@ def write_func_lvar(self, local_vars):
13991427

14001428
def write_func(self, qual_ret, name, body, args=None, local_vars=None):
14011429
self.write_func_prot(qual_ret=qual_ret, name=name, args=args)
1430+
self.block_start()
14021431
self.write_func_lvar(local_vars=local_vars)
14031432

1404-
self.block_start()
14051433
for line in body:
14061434
self.p(line)
14071435
self.block_end()
@@ -1644,11 +1672,23 @@ def put_req_nested_prototype(ri, struct, suffix=';'):
16441672

16451673

16461674
def put_req_nested(ri, struct):
1675+
local_vars = []
1676+
init_lines = []
1677+
1678+
local_vars.append('struct nlattr *nest;')
1679+
init_lines.append("nest = ynl_attr_nest_start(nlh, attr_type);")
1680+
1681+
for _, arg in struct.member_list():
1682+
if arg.presence_type() == 'count':
1683+
local_vars.append('unsigned int i;')
1684+
break
1685+
16471686
put_req_nested_prototype(ri, struct, suffix='')
16481687
ri.cw.block_start()
1649-
ri.cw.write_func_lvar('struct nlattr *nest;')
1688+
ri.cw.write_func_lvar(local_vars)
16501689

1651-
ri.cw.p("nest = ynl_attr_nest_start(nlh, attr_type);")
1690+
for line in init_lines:
1691+
ri.cw.p(line)
16521692

16531693
for _, arg in struct.member_list():
16541694
arg.attr_put(ri, "obj")
@@ -1850,6 +1890,11 @@ def print_req(ri):
18501890
local_vars += ['size_t hdr_len;',
18511891
'void *hdr;']
18521892

1893+
for _, attr in ri.struct["request"].member_list():
1894+
if attr.presence_type() == 'count':
1895+
local_vars += ['unsigned int i;']
1896+
break
1897+
18531898
print_prototype(ri, direction, terminate=False)
18541899
ri.cw.block_start()
18551900
ri.cw.write_func_lvar(local_vars)
@@ -2941,6 +2986,9 @@ def main():
29412986
for attr_set, struct in parsed.pure_nested_structs.items():
29422987
ri = RenderInfo(cw, parsed, args.mode, "", "", attr_set)
29432988
print_type_full(ri, struct)
2989+
if struct.request and struct.in_multi_val:
2990+
free_rsp_nested_prototype(ri)
2991+
cw.nl()
29442992

29452993
for op_name, op in parsed.ops.items():
29462994
cw.p(f"/* ============== {op.enum_name} ============== */")

0 commit comments

Comments
 (0)