Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

shell/cord_ep: Add user guidance & prevent accidental crash #18053

Merged
merged 1 commit into from Oct 6, 2022

Conversation

Teufelchen1
Copy link
Contributor

Contribution description

  • (Everything was done on the lastest master as of 2022-05-04T10:00)
  • This PR only touches the shell command handling of cord_ep
  • Not sure if I want to call it a fix; It fixes an issue where running the subcommand cord_ep register just slightly wrong, an assertion in gcoap.c would get triggered - resulting in a RIOT kernel panic.
  • I consider this behaviour to be a bug, reasoning that a shell should be able to cope with users that do not exactly know what they are doing. (Go figure who that user was 😇)
  • This PR corrects this behaviour by doing a short sanity check on the user input - yielding an error if necessary.

Testing procedure

For reproducing the bug do:

  1. Go to RIOT/examples/cord_ep/ and run make all flash term for a board of your choice
  2. Inside the RIOT shell, run cord_ep register [fd00::1]:1234 foo (the exact host:port combination does not matter, just have to be valid)
  3. Make sure that the registration interface (in my example foo) does not start with a /
  4. Observe a thrown failed assertion i.g., *** RIOT kernel panic: FAILED ASSERTION.

After applying my suggested fix:

  1. Go to RIOT/examples/cord_ep/ and run make all flash term for a board of your choice
  2. Inside the RIOT shell, run cord_ep register [fd00::1]:1234 foo (the exact host:port combination does not matter, just have to be valid)
  3. Make sure that the registration interface (in my example foo) does not start with a /
  4. The command responds with an error: error: registration interface must start with '/'

@github-actions github-actions bot added the Area: sys Area: System label May 4, 2022
@@ -63,6 +63,10 @@ int _cord_ep_handler(int argc, char **argv)
}
if (argc > 3) {
regif = argv[3];
if (regif[0] != '/') {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it makes sense just to change the command and accept an URI, which we parse with https://doc.riot-os.org/group__sys__uri__parser.html ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. A reasonable suggestion but should the shell command enforce that the registration interface is a valid uri?
At the moment the chain of responsibility is:

  1. registration interface -> defined somewhere in some coap related rfc
  2. gcoap_req_init() -> uses a registration interface
  3. gcoap_req_init() -> enforces some bare minimal expectation how a registration interface should look like (mostly for programming safety I assume, didn't look deeply at it)
  4. cord_ep_register() -> passes a registration interface(without any checks on it, beside a convenience NULL handling) to gcoap_req_init()
  5. _cord_ep_handler() -> calls cord_ep_register() with a user given registration interface (without any checks on it)
  6. the user -> "Generates" a registration interface and calls _cord_ep_handler() with it (maybe with checks, maybe without, users tend to be unreliable 😬)

Given this chain & your proposal, I think I could look up in coap / the rfc how exactly a registration interface may and or must look like (URI...). After that is clarified (at least for me :p) one should enforce that as close to the rfc as possible (in the chain). One aspect that is important for deciding this is performance / code size etc. E.g. a heavy URI check may not be wanted in 3. gcoap, assuming that only other software interacts with it(but not users). This would delegate that responsibility to 4. cord_ep_register().
Enforcing the registration interface to be compliant with a given uri parser inside the shell command, while the e.g. cord_ep_register() could perfectly work with a non uri compliant registration interface, could become confusing.

E.g. A user could find that a given registration interface works in his/her own code but not in the shell. This is also the reason why I tried to match the assert as close as possible and didn't add any other checks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given this chain & your proposal, I think I could look up in coap / the rfc how exactly a registration interface may and or must look like (URI...). After that is clarified (at least for me :p) one should enforce that as close to the rfc as possible (in the chain). One aspect that is important for deciding this is performance / code size etc. E.g. a heavy URI check may not be wanted in 3. gcoap, assuming that only other software interacts with it(but not users). This would delegate that responsibility to 4. cord_ep_register(). Enforcing the registration interface to be compliant with a given uri parser inside the shell command, while the e.g. cord_ep_register() could perfectly work with a non uri compliant registration interface, could become confusing.

E.g. A user could find that a given registration interface works in his/her own code but not in the shell. This is also the reason why I tried to match the assert as close as possible and didn't add any other checks.

As I understand this will always end up being a valid URI. We need to get from the command the RD address (maybe port) pointing to a CoAP endpoint, and CoAP path (i.e. the interface). I think unifying the shell commands through our examples is a big gain, then we don't re-implement parsers each time. My proposal is to merge the argument 2 and 3 (remote and interface) into a single URI.

@benpicco benpicco requested a review from chrysn May 8, 2022 20:48
@Teufelchen1 Teufelchen1 changed the title shell/cord_ep: Add user guidance & prevent accidental crash WIP: shell/cord_ep: Add user guidance & prevent accidental crash May 11, 2022
@chrysn
Copy link
Member

chrysn commented Sep 22, 2022

The RFC is of little help here -- it only deals in URIs (and not URI references); the argument to cord_ep register is neither. (We could make it a limited URI reference, but #18622 shows it's not there now).

Going through a full URI here is one solution, but then it should be applied consistently both here and to the coap commands of the gcoap example (which, by the way, suffer the same bug). The current PR does that, and it's looking good at first glance.

(I think we should also do that for the gcoap example. Doesn't need to be, probably even shouldn't be, in this PR -- setting an example here puts a bit of pressure on the other example).

One important distinction is getting a bit lost here, though: With an RD, you can either start with a host (and then perform autodiscovery) or with a resource (like, the user did the discovery, here's the URI to go to). That resource could even be / (it's a corner case but definitely possible). With the current interface, that distinction is not visible any more. I think that the distinction is implicit here because uri_result.path might be NULL and thus trigger auto-discovery, and that's something the user can work with (esp. if it's communicated well); I'm giving it a try.


By the way, is this still WIP?

Copy link
Member

@chrysn chrysn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good; see above for nits and comments.

If you remove the WIP and declare it done from your side, I think this can go in.

sys/shell/cmds/cord_ep.c Outdated Show resolved Hide resolved
Comment on lines 73 to 92
if (uri_result.ipv6addr == NULL) {
puts("error: Only ipv6 addresses are supported");
return 1;
}

sock_udp_ep_t remote;
if (make_sock_ep(&remote, argv[2]) < 0) {
printf("error: unable to parse address\n");
remote.family = AF_INET6;
remote.netif = SOCK_ADDR_ANY_NETIF;
if (!ipv6_addr_from_buf((ipv6_addr_t *)&remote.addr.ipv6, uri_result.ipv6addr,
uri_result.ipv6addr_len)) {
puts("error: IPv6 address malformed");
return 1;
}
if (argc > 3) {
regif = argv[3];

if (uri_result.port == 0) {
remote.port = COAP_PORT;
}
else {
remote.port = uri_result.port;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could go into a helper function (possibly part of the URI parsing module) that extracts a sock_udp_ep_t from a parsed URI (being provided a default port).

(Then, also, that'd be a unified place where handling DNS names could be done, or legacy IP versions could be handled if anyone cared).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pssssst 🤫 you are leaking my secret plans for the uri parser.

I'm going to move the uri_parser discussion in separate issue. :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine with me; all the more reason to get this done, so you can follow up, and #18622 will become easy :-)

sys/shell/cmds/cord_ep.c Show resolved Hide resolved
@chrysn chrysn added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Area: CoAP Area: Constrained Application Protocol implementations and removed Area: sys Area: System labels Sep 22, 2022
@Teufelchen1
Copy link
Contributor Author

The RFC is of little help here -- it only deals in URIs (and not URI references); the argument to cord_ep register is neither. (We could make it a limited URI reference, but #18622 shows it's not there now).

What ever we do, I strongly suggest to unify the ux/ui - as already pointed out by Leandro. "I think unifying the shell commands through our examples is a big gain, then we don't re-implement parsers each time."

Going through a full URI here is one solution,
[...]
-- setting an example here puts a bit of pressure on the other example).

😈

One important distinction is getting a bit lost here, though: With an RD, you can either start with a host (and then perform autodiscovery) or with a resource (like, the user did the discovery, here's the URI to go to). That resource could even be / (it's a corner case but definitely possible). With the current interface, that distinction is not visible any more. I think that the distinction is implicit here because uri_result.path might be NULL and thus trigger auto-discovery, and that's something the user can work with (esp. if it's communicated well); I'm giving it a try.

Don't forget that cord_ep discover <address> still exist! If you actively want to discover the resource, you still can do so and it is not a hidden feature. Additionally, resorting to auto discovery when using register without providing a resource is a good ux for a shell command. It is a bit of a pity that / is no longer distinguishable but imo acceptable for a shell command. Given my own experience, shell commands are the first things a newcomer is going to play with in riot, they should be simple, helpful and friendly. "Professional users" writing "production software" aren't likely to use shell commands in production - those are not affected by this / edge-case.

By the way, is this still WIP?

Yes! Since this file is now outdated. I would have fixed it yesterday but sadly this part of riot is either completely undocumented or I couldn't find documentation about it. This caused me to waste so much time on getting this "test" to run & understand that I lost motivation and called it a day....

@github-actions github-actions bot added Area: sys Area: System and removed Area: CoAP Area: Constrained Application Protocol implementations labels Sep 22, 2022
@chrysn
Copy link
Member

chrysn commented Sep 22, 2022

Don't forget that cord_ep discover <address> still exist!

I did indeed miss it. It's good to have it around so users are able to introspect what's happening -- and if I understand your sentiment right, things will still Just Work especially for users who don't provide a path and get auto-discovery.

I would have fixed it yesterday but sadly this part of riot is either completely undocumented or I couldn't find documentation about it.

I feel this, riotctl is a cluster of things (configuration? building? CLI abstraction?) that I don't get myself either, and only fix superficially whenever something breaks. Before you get stuck, don't hesitate to ping is authors for help. Tests should keep software good, but not at the cost of keeping it from getting better.

sys/shell/cmds/cord_ep.c Outdated Show resolved Hide resolved
@chrysn
Copy link
Member

chrysn commented Sep 22, 2022 via email

@chrysn
Copy link
Member

chrysn commented Sep 22, 2022

One more request before I ACK this: Please ensure the commit message is current; I suggest something like "shell/cord_ep: Take full URIs instead of IP and path" / / "This fixes a crash when the path was not entered with a leading slash."

[note to self: And then there's the case of riotctrl_shell/tests that I have no clue how to go about other than pinging people on Matrix]

@chrysn
Copy link
Member

chrysn commented Sep 23, 2022

Having spent some time with the riotctrl_shell/cord_ep, I don't think that file needs changes. Given that it does nothing to abstract, and where it does (by naming arguments) it does wrongly (it says "uri", which is correct now but wasn't correct before), it can stay as it is, and its callers will need to adjust. As the release tests are maintained out-of-tree, this will only happen after this PR is in. (It may also happen to be practical to just move this test in-tree).

This fixes a crash when the path was not entered with a leading slash.
@Teufelchen1 Teufelchen1 changed the title WIP: shell/cord_ep: Add user guidance & prevent accidental crash shell/cord_ep: Add user guidance & prevent accidental crash Sep 27, 2022
@kaspar030 kaspar030 added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Sep 27, 2022
@kaspar030 kaspar030 added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Sep 27, 2022
@Teufelchen1
Copy link
Contributor Author

Ping @chrysn -
Murdock is stuck at "Expected — Waiting for status to be reported" what ever that means. Beside that, hit merge? 🥺❤️

@chrysn chrysn merged commit edfa255 into RIOT-OS:master Oct 6, 2022
@chrysn
Copy link
Member

chrysn commented Oct 6, 2022

Thanks for fixing this!

miri64 added a commit to miri64/RIOT that referenced this pull request Oct 10, 2022
The argument regif was removed from the shell command in RIOT-OS#18053,
so there is not much need to keep it in the ShellInteraction for that command.
miri64 added a commit to miri64/RIOT that referenced this pull request Oct 10, 2022
The argument regif was removed from the shell command in RIOT-OS#18053,
so there is not much need to keep it in the ShellInteraction for that command.
@maribu maribu added this to the Release 2022.10 milestone Oct 14, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: sys Area: System CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants