mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 00:53:34 +02:00
XDR enum decoders generated by xdrgen do not verify that incoming
values are valid members of the enum. Incoming out-of-range values
from malicious or buggy peers propagate through the system
unchecked.
Add validation logic to generated enum decoders using a switch
statement that explicitly lists valid enumerator values. The
compiler optimizes this to a simple range check when enum values
are dense (contiguous), while correctly rejecting invalid values
for sparse enums with gaps in their value ranges.
The --no-enum-validation option on the source subcommand disables
this validation when not needed.
The minimum and maximum fields in _XdrEnum, which were previously
unused placeholders for a range-based validation approach, have
been removed since the switch-based validation handles both dense
and sparse enums correctly.
Because the new mechanism results in substantive changes to
generated code, existing .x files are regenerated. Unrelated white
space and semicolon changes in the generated code are due to recent
commit 1c873a2fd1 ("xdrgen: Don't generate unnecessary semicolon")
and commit 38c4df91242b ("xdrgen: Address some checkpatch whitespace
complaints").
Reviewed-by: NeilBrown <neil@brown.name>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
72 lines
2.8 KiB
Python
72 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
# ex: set filetype=python:
|
|
|
|
"""Generate code to handle XDR enum types"""
|
|
|
|
from generators import SourceGenerator, create_jinja2_environment
|
|
from xdr_ast import _XdrEnum, public_apis, big_endian, get_header_name
|
|
from xdr_parse import get_xdr_enum_validation
|
|
|
|
|
|
class XdrEnumGenerator(SourceGenerator):
|
|
"""Generate source code for XDR enum types"""
|
|
|
|
def __init__(self, language: str, peer: str):
|
|
"""Initialize an instance of this class"""
|
|
self.environment = create_jinja2_environment(language, "enum")
|
|
self.peer = peer
|
|
|
|
def emit_declaration(self, node: _XdrEnum) -> None:
|
|
"""Emit one declaration pair for an XDR enum type"""
|
|
if node.name in public_apis:
|
|
template = self.environment.get_template("declaration/enum.j2")
|
|
print(template.render(name=node.name))
|
|
|
|
def emit_definition(self, node: _XdrEnum) -> None:
|
|
"""Emit one definition for an XDR enum type"""
|
|
template = self.environment.get_template("definition/open.j2")
|
|
print(template.render(name=node.name))
|
|
|
|
template = self.environment.get_template("definition/enumerator.j2")
|
|
for enumerator in node.enumerators:
|
|
print(template.render(name=enumerator.name, value=enumerator.value))
|
|
|
|
if node.name in big_endian:
|
|
template = self.environment.get_template("definition/close_be.j2")
|
|
else:
|
|
template = self.environment.get_template("definition/close.j2")
|
|
print(template.render(name=node.name))
|
|
|
|
def emit_decoder(self, node: _XdrEnum) -> None:
|
|
"""Emit one decoder function for an XDR enum type"""
|
|
if node.name in big_endian:
|
|
template = self.environment.get_template("decoder/enum_be.j2")
|
|
else:
|
|
template = self.environment.get_template("decoder/enum.j2")
|
|
print(
|
|
template.render(
|
|
name=node.name,
|
|
enumerators=node.enumerators,
|
|
validate=get_xdr_enum_validation(),
|
|
)
|
|
)
|
|
|
|
def emit_encoder(self, node: _XdrEnum) -> None:
|
|
"""Emit one encoder function for an XDR enum type"""
|
|
if node.name in big_endian:
|
|
template = self.environment.get_template("encoder/enum_be.j2")
|
|
else:
|
|
template = self.environment.get_template("encoder/enum.j2")
|
|
print(template.render(name=node.name))
|
|
|
|
def emit_maxsize(self, node: _XdrEnum) -> None:
|
|
"""Emit one maxsize macro for an XDR enum type"""
|
|
macro_name = get_header_name().upper() + "_" + node.name + "_sz"
|
|
template = self.environment.get_template("maxsize/enum.j2")
|
|
print(
|
|
template.render(
|
|
macro=macro_name,
|
|
width=" + ".join(node.symbolic_width()),
|
|
)
|
|
)
|