* [PATCH v2 net-next 0/2] update NULL pointer handling in generated code
@ 2026-08-07 17:14 Thaison Phan
2026-08-07 17:14 ` [PATCH v2 net-next 1/2] tools: ynl: check for null ptr on dump free Thaison Phan
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Thaison Phan @ 2026-08-07 17:14 UTC (permalink / raw)
To: Jakub Kicinski, Donald Hunter, David S . Miller , Eric Dumazet,
Paolo Abeni
Cc: Simon Horman, Fengyuan Gong, Stan Iliev,
Asbjørn Sloth Tønnesen, Matthieu Baerts (NGI0),
Thaison Phan, netdev, linux-kernel
This series fixes potential NULL pointer dereferences in YNL-generated C
code during dump list freeing and memory allocation in parsing getters.
Changes in v2:
- Moved null check in dump list free to be separate from while loop
- Updated allocation checks to only be for getters as setters will
be handled in a separate patch.
Testing:
- Regenerated all c headers/sources under tools/net/ynl/generated/
- Built libynl, ynltool, and test binaries without errors or warnings
- Ran make target run_tests in tools/net/ynl/tests successfully
- Ran tools/testing/selftests/drivers/net/psp.py in QEMU x86_64
successfully
v1:
https://lore.kernel.org/netdev/20260803201652.2752685-1-thaisonphan@google.com/
Thaison Phan (2):
tools: ynl: check for null ptr on dump free
tools: ynl: check alloc fails in generated getter code
tools/net/ynl/pyynl/ynl_gen_c.py | 35 ++++++++++++++++++++++++--------
1 file changed, 27 insertions(+), 8 deletions(-)
--
2.55.0.654.g21b8a5bc05-goog
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH v2 net-next 1/2] tools: ynl: check for null ptr on dump free 2026-08-07 17:14 [PATCH v2 net-next 0/2] update NULL pointer handling in generated code Thaison Phan @ 2026-08-07 17:14 ` Thaison Phan 2026-08-07 17:15 ` [PATCH v2 net-next 2/2] tools: ynl: check alloc fails in generated getter code Thaison Phan 2026-08-11 1:30 ` [PATCH v2 net-next 0/2] update NULL pointer handling in generated code patchwork-bot+netdevbpf 2 siblings, 0 replies; 4+ messages in thread From: Thaison Phan @ 2026-08-07 17:14 UTC (permalink / raw) To: Jakub Kicinski, Donald Hunter, David S . Miller , Eric Dumazet, Paolo Abeni Cc: Simon Horman, Fengyuan Gong, Stan Iliev, Asbjørn Sloth Tønnesen, Matthieu Baerts (NGI0), Thaison Phan, netdev, linux-kernel Static analysis detected code paths where freeing a dump list after early errors when creating the corresponding dump list like in ynl_exec_dump() can result in a null pointer dereference since the first node in the ynl_dump_state would still be zero initialized. To prevent this potential problem updated the ynl c generation script to check for a NULL pointer before continuing to free the nodes in a dump list. Signed-off-by: Thaison Phan <thaisonphan@google.com> --- v1 -> v2: Updated to check for NULL outside of while loop to make intent of check more clear since there can not be a NULL while iterating the list (Suggested by Jakub Kicinski) v1: https://lore.kernel.org/netdev/20260803201652.2752685-2-thaisonphan@google.com/ tools/net/ynl/pyynl/ynl_gen_c.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index cdc3646f2642..95502dbaec94 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -2747,6 +2747,9 @@ def print_dump_type_free(ri): ri.cw.block_start() ri.cw.p(f"{sub_type} *next = rsp;") ri.cw.nl() + ri.cw.p('if (!next)') + ri.cw.p('return;') + ri.cw.nl() ri.cw.block_start(line='while ((void *)next != YNL_LIST_END)') _free_type_members_iter(ri, ri.struct['reply']) ri.cw.p('rsp = next;') -- 2.55.0.654.g21b8a5bc05-goog ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 net-next 2/2] tools: ynl: check alloc fails in generated getter code 2026-08-07 17:14 [PATCH v2 net-next 0/2] update NULL pointer handling in generated code Thaison Phan 2026-08-07 17:14 ` [PATCH v2 net-next 1/2] tools: ynl: check for null ptr on dump free Thaison Phan @ 2026-08-07 17:15 ` Thaison Phan 2026-08-11 1:30 ` [PATCH v2 net-next 0/2] update NULL pointer handling in generated code patchwork-bot+netdevbpf 2 siblings, 0 replies; 4+ messages in thread From: Thaison Phan @ 2026-08-07 17:15 UTC (permalink / raw) To: Jakub Kicinski, Donald Hunter, David S . Miller , Eric Dumazet, Paolo Abeni Cc: Simon Horman, Fengyuan Gong, Stan Iliev, Asbjørn Sloth Tønnesen, Matthieu Baerts (NGI0), Thaison Phan, netdev, linux-kernel Generated YNL getter code does not check the return value of malloc() and calloc() before passing the resulting pointer to memcpy(). This could lead to a NULL pointer dereference on memory allocation failure. Updated the C code generator to check for allocation failures and to return an error code in getters. Signed-off-by: Thaison Phan <thaisonphan@google.com> --- v1 -> v2: Removed updates to allocation checks in setters as those can be fixed in a separate patch. (Suggested by Jakub Kicinski) v1: https://lore.kernel.org/netdev/20260803201652.2752685-3-thaisonphan@google.com/ tools/net/ynl/pyynl/ynl_gen_c.py | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/tools/net/ynl/pyynl/ynl_gen_c.py b/tools/net/ynl/pyynl/ynl_gen_c.py index 95502dbaec94..2b3483db1b60 100755 --- a/tools/net/ynl/pyynl/ynl_gen_c.py +++ b/tools/net/ynl/pyynl/ynl_gen_c.py @@ -526,8 +526,10 @@ class TypeString(Type): def _attr_get(self, ri, var): len_mem = var + '->_len.' + self.c_name - return [f"{len_mem} = len;", - f"{var}->{self.c_name} = malloc(len + 1);", + return [f"{var}->{self.c_name} = malloc(len + 1);", + f"if (!{var}->{self.c_name})", + "return YNL_PARSE_CB_ERROR;", + f"{len_mem} = len;", f"memcpy({var}->{self.c_name}, ynl_attr_get_str(attr), len);", f"{var}->{self.c_name}[len] = 0;"], \ ['len = strnlen(ynl_attr_get_str(attr), ynl_attr_data_len(attr));'], \ @@ -582,8 +584,10 @@ class TypeBinary(Type): def _attr_get(self, ri, var): len_mem = var + '->_len.' + self.c_name - return [f"{len_mem} = len;", - f"{var}->{self.c_name} = malloc(len);", + return [f"{var}->{self.c_name} = malloc(len);", + f"if (!{var}->{self.c_name})", + "return YNL_PARSE_CB_ERROR;", + f"{len_mem} = len;", f"memcpy({var}->{self.c_name}, ynl_attr_data(attr), len);"], \ ['len = ynl_attr_data_len(attr);'], \ ['unsigned int len;'] @@ -601,11 +605,13 @@ class TypeBinaryStruct(TypeBinary): def _attr_get(self, ri, var): struct_sz = 'sizeof(struct ' + c_lower(self.get("struct")) + ')' len_mem = var + '->_' + self.presence_type() + '.' + self.c_name - return [f"{len_mem} = len;", - f"if (len < {struct_sz})", + return [f"if (len < {struct_sz})", f"{var}->{self.c_name} = calloc(1, {struct_sz});", "else", f"{var}->{self.c_name} = malloc(len);", + f"if (!{var}->{self.c_name})", + "return YNL_PARSE_CB_ERROR;", + f"{len_mem} = len;", f"memcpy({var}->{self.c_name}, ynl_attr_data(attr), len);"], \ ['len = ynl_attr_data_len(attr);'], \ ['unsigned int len;'] @@ -631,9 +637,11 @@ class TypeBinaryScalarArray(TypeBinary): def _attr_get(self, ri, var): len_mem = var + '->_count.' + self.c_name - return [f"{len_mem} = len / sizeof(__{self.get('sub-type')});", - f"len = {len_mem} * sizeof(__{self.get('sub-type')});", + return [f"len = (len / sizeof(__{self.get('sub-type')})) * sizeof(__{self.get('sub-type')});", f"{var}->{self.c_name} = malloc(len);", + f"if (!{var}->{self.c_name})", + "return YNL_PARSE_CB_ERROR;", + f"{len_mem} = len / sizeof(__{self.get('sub-type')});", f"memcpy({var}->{self.c_name}, ynl_attr_data(attr), len);"], \ ['len = ynl_attr_data_len(attr);'], \ ['unsigned int len;'] @@ -2227,6 +2235,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.block_start(line=f"if (n_{aspec.c_name})") ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") + ri.cw.p(f"if (!dst->{aspec.c_name})") + ri.cw.p("return YNL_PARSE_CB_ERROR;") ri.cw.p(f"dst->_count.{aspec.c_name} = n_{aspec.c_name};") ri.cw.p('i = 0;') if 'nested-attributes' in aspec: @@ -2252,6 +2262,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): aspec = struct[arg] ri.cw.block_start(line=f"if (n_{aspec.c_name})") ri.cw.p(f"dst->{aspec.c_name} = calloc(n_{aspec.c_name}, sizeof(*dst->{aspec.c_name}));") + ri.cw.p(f"if (!dst->{aspec.c_name})") + ri.cw.p("return YNL_PARSE_CB_ERROR;") ri.cw.p(f"dst->_count.{aspec.c_name} = n_{aspec.c_name};") ri.cw.p('i = 0;') if 'nested-attributes' in aspec: @@ -2275,6 +2287,8 @@ def _multi_parse(ri, struct, init_lines, local_vars): ri.cw.nl() ri.cw.p('len = strnlen(ynl_attr_get_str(attr), ynl_attr_data_len(attr));') ri.cw.p(f'dst->{aspec.c_name}[i] = malloc(sizeof(struct ynl_string) + len + 1);') + ri.cw.p(f"if (!dst->{aspec.c_name}[i])") + ri.cw.p("return YNL_PARSE_CB_ERROR;") ri.cw.p(f"dst->{aspec.c_name}[i]->len = len;") ri.cw.p(f"memcpy(dst->{aspec.c_name}[i]->str, ynl_attr_get_str(attr), len);") ri.cw.p(f"dst->{aspec.c_name}[i]->str[len] = 0;") @@ -2434,6 +2448,8 @@ def print_req(ri): if 'reply' in ri.op[ri.op_mode]: ri.cw.p('rsp = calloc(1, sizeof(*rsp));') + ri.cw.p('if (!rsp)') + ri.cw.p(f'return {ret_err};') ri.cw.p('yrs.yarg.data = rsp;') ri.cw.p(f"yrs.cb = {op_prefix(ri, 'reply')}_parse;") if ri.op.value is not None: -- 2.55.0.654.g21b8a5bc05-goog ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 net-next 0/2] update NULL pointer handling in generated code 2026-08-07 17:14 [PATCH v2 net-next 0/2] update NULL pointer handling in generated code Thaison Phan 2026-08-07 17:14 ` [PATCH v2 net-next 1/2] tools: ynl: check for null ptr on dump free Thaison Phan 2026-08-07 17:15 ` [PATCH v2 net-next 2/2] tools: ynl: check alloc fails in generated getter code Thaison Phan @ 2026-08-11 1:30 ` patchwork-bot+netdevbpf 2 siblings, 0 replies; 4+ messages in thread From: patchwork-bot+netdevbpf @ 2026-08-11 1:30 UTC (permalink / raw) To: Thaison Phan Cc: kuba, donald.hunter, davem, edumazet, pabeni, horms, gfengyuan, stani, ast, matttbe, netdev, linux-kernel Hello: This series was applied to netdev/net-next.git (main) by Jakub Kicinski <kuba@kernel.org>: On Fri, 7 Aug 2026 17:14:58 +0000 you wrote: > This series fixes potential NULL pointer dereferences in YNL-generated C > code during dump list freeing and memory allocation in parsing getters. > > Changes in v2: > - Moved null check in dump list free to be separate from while loop > - Updated allocation checks to only be for getters as setters will > be handled in a separate patch. > > [...] Here is the summary with links: - [v2,net-next,1/2] tools: ynl: check for null ptr on dump free https://git.kernel.org/netdev/net-next/c/7c62c481bb43 - [v2,net-next,2/2] tools: ynl: check alloc fails in generated getter code https://git.kernel.org/netdev/net-next/c/153f709c8639 You are awesome, thank you! -- Deet-doot-dot, I am a bot. https://korg.docs.kernel.org/patchwork/pwbot.html ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-08-11 1:30 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-07 17:14 [PATCH v2 net-next 0/2] update NULL pointer handling in generated code Thaison Phan 2026-08-07 17:14 ` [PATCH v2 net-next 1/2] tools: ynl: check for null ptr on dump free Thaison Phan 2026-08-07 17:15 ` [PATCH v2 net-next 2/2] tools: ynl: check alloc fails in generated getter code Thaison Phan 2026-08-11 1:30 ` [PATCH v2 net-next 0/2] update NULL pointer handling in generated code patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox