fix(docker): parse a /proc port at 16 bits, not 32 (CodeQL alert 8) - #343
Merged
Conversation
hexPort parsed the port field of /proc/net/tcp at bit size 32 and converted the result to int. That is only correct where int is 64 bits. On a 32-bit build the conversion wraps silently: measured with a GOARCH=386 binary, "0100007F:FFFFFFFF" comes back as -1 with ok=true, and at 64 bits as 4294967295 — in both cases a number the caller then compares against a port. A TCP port is 16 bits and the kernel writes the field as %04X, so nothing it produces reaches the wrap and no hostile input gets here; the consequence would be a missed match, and the port-owner diagnostic falling back to its generic message. Parsing at the type's real width makes the range check the parser's job rather than a rule the next caller has to remember. Closes CodeQL alert 8 (go/incorrect-integer-conversion). Tests fail against the old parser at 64 bits: hexPort accepts FFFFFFFF/80000000/10000, and parseListeningInodes matches a row whose port field is not a port. A control asserts a real port still parses. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ako
pushed a commit
that referenced
this pull request
Aug 31, 2026
`filter($L, Amount > 0)` was stored as `Microflows$FilterByExpression` with the authored text verbatim. Mendix evaluates that expression once per item with the item bound to `$currentObject`, where a bare attribute name is not valid — so mxbuild reported CE0117 while `mxcli check` passed. This is the unfinished half of bug #343. That fix rerouted `attr = value` to `Microflows$Filter` (filter BY ATTRIBUTE), which takes a member name rather than an expression and so accepts the bare form. Every other predicate still fell through to the expression shape, which made the split turn on the OPERATOR and be invisible to the author: `Status = 'x'` built and `Status != 'x'` did not. Not a Mendix version change, despite the report: the same 19-microflow probe produces the identical 7 errors on mxbuild 11.11.0 and 11.13.0. - A bare name that provably resolves to a member of the list's element entity is rewritten to `$currentObject/<member>` (an association keeps its module qualifier, an attribute does not). A name that does not resolve is refused rather than left to surface as CE0117. When the element entity cannot be determined nothing is proven either way, so the predicate is passed through. - The predicate can reach the builder as a frozen `SourceExpr`, so the rewrite patches the source text too, skipping single-quoted literals — the `'Amount'` in `filter($L, Qty > 0 and Status != 'Amount')` must survive untouched. - MDL-LISTOP01 refuses an iterator variable that is not in scope, pre-empting CE0109. It keys on scope rather than on the name, so `$item` stays valid as an enclosing loop's iterator — the shape of CLAUDE.md's O(N) `find` idiom. - The `syntax microflow.list-operations` example no longer teaches a form that only compiles through the `=` reroute, and notes that SORT is not an expression, so a bare attribute is the only spelling there. Control: stubbing the qualifier takes the repro from 0 to 7 × CE0117 with the two `=` cases staying green, which is also the #343 regression guard. Repros: mdl-examples/bug-tests/1002-filter-find-bare-attribute.mdl (0 errors on mxbuild 11.13.0) and 1002-filter-bad-iterator.fail.mdl. Closes mendixlabs#1002 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017s476QkXr9CFMvKspVzcvu
ako
pushed a commit
that referenced
this pull request
Sep 1, 2026
`filter($L, Amount > 0)` was stored as `Microflows$FilterByExpression` with the authored text verbatim. Mendix evaluates that expression once per item with the item bound to `$currentObject`, where a bare attribute name is not valid — so mxbuild reported CE0117 while `mxcli check` passed. This is the unfinished half of bug #343. That fix rerouted `attr = value` to `Microflows$Filter` (filter BY ATTRIBUTE), which takes a member name rather than an expression and so accepts the bare form. Every other predicate still fell through to the expression shape, which made the split turn on the OPERATOR and be invisible to the author: `Status = 'x'` built and `Status != 'x'` did not. Not a Mendix version change, despite the report: the same 19-microflow probe produces the identical 7 errors on mxbuild 11.11.0 and 11.13.0. - A bare name that provably resolves to a member of the list's element entity is rewritten to `$currentObject/<member>` (an association keeps its module qualifier, an attribute does not). A name that does not resolve is refused rather than left to surface as CE0117. When the element entity cannot be determined nothing is proven either way, so the predicate is passed through. - The predicate can reach the builder as a frozen `SourceExpr`, so the rewrite patches the source text too, skipping single-quoted literals — the `'Amount'` in `filter($L, Qty > 0 and Status != 'Amount')` must survive untouched. - MDL-LISTOP01 refuses an iterator variable that is not in scope, pre-empting CE0109. It keys on scope rather than on the name, so `$item` stays valid as an enclosing loop's iterator — the shape of CLAUDE.md's O(N) `find` idiom. - The `syntax microflow.list-operations` example no longer teaches a form that only compiles through the `=` reroute, and notes that SORT is not an expression, so a bare attribute is the only spelling there. Control: stubbing the qualifier takes the repro from 0 to 7 × CE0117 with the two `=` cases staying green, which is also the #343 regression guard. Repros: mdl-examples/bug-tests/1002-filter-find-bare-attribute.mdl (0 errors on mxbuild 11.13.0) and 1002-filter-bad-iterator.fail.mdl. Closes mendixlabs#1002 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017s476QkXr9CFMvKspVzcvu
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes CodeQL alert 8,
go/incorrect-integer-conversion(high), atcmd/mxcli/docker/portowner_linux.go:121.What it is
hexPortreads the port out of a/proc/net/tcplocal_addressfield:Parsing at 32 bits and narrowing to
intis only correct whereintis 64 bits. Measured with aGOARCH=386binary (which runs on an amd64 host, so this is observed rather than argued):0100007F:1F908080, true8080, true0100007F:FFFFFFFF@ 64-bit4294967295, true0, false0100007F:FFFFFFFF@ 32-bit-1, true0, falseHow bad it is
Not exploitable, and I'd rate it informational rather than high:
/proc/net/tcp, written by the kernel, which formats the port%04X— no value wider than 16 bits is ever there, and nothing user-supplied reaches this function;p != portfailing to match, so the port-owner lookup returns nothing and the guard falls back to its generic "port in use" message. No memory unsafety, no bypass;mdl/settingsoverlay/settingsoverlay.go:45has9007199254740992as an untypedintconstant).Why fix it anyway
A TCP port is 16 bits, so 16 is simply the right width, and parsing at the target type's width moves the range check into the parser instead of leaving it as a rule the next caller has to remember. It's a one-token change, and the alert otherwise stays open.
Tests
Both new tests fail against the old parser at 64 bits — verified by reverting the fix:
TestHexPort_RefusesAValueWiderThanAPortopens with the control that a real port (8080) still parses, so the fix can't pass by refusing everything. The out-of-range literal is writtenint(^uint32(0))rather than4294967295, which is not a validintconstant on a 32-bit build.Symptom row appended to
.claude/skills/fix-issue.md.🤖 Generated with Claude Code