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

control: Limit memory use by control connections. #208

Merged
merged 1 commit into from
Jul 26, 2023

Conversation

mobin-2008
Copy link
Collaborator

@mobin-2008 mobin-2008 commented Jul 22, 2023

Hi.

I working on this PR for resolving one of the last blockers for 0.17 release:

dinit/TODO

Lines 3 to 5 in 7d491be

* Limit memory use by control connections. Currently clients have command responses queued without
limit; it would be better to stop accepting new commands once a certain amount of response is
buffered.

Signed-off-by: Mobin "Hojjat' Aydinfar <[email protected]>

@mobin-2008 mobin-2008 added Enhancement/New Feature Improving things or introduce new feature A-Importance: Normal C-dinitctl Things about dinitctl C-dinit Things about the main parts of dinit labels Jul 22, 2023
@davmac314
Copy link
Owner

The idea is not to reject commands if the buffer is too full, but to stop receiving them until the buffer has had a chance to reduce. That would be done by disabling the read watch (IN_EVENTS) in the control_conn_watcher (and then enabling the read watch again once the buffer was below a threshold).

This solution as written doesn't actually address the problem that the TODO note is concerned with, which is that a malicious or badly-written client could keep stuffing the output buffer causing it to consume an excessive amount of memory. I.e. this solution requires that the buffer management is performed by the client itself, which doesn't help.

(Note that in practice a malicious client already needs to be root to be able to send commands via the control socket, so this is mostly a theoretical concern).

Just FYI there's also an error in your implementation that means it always returns DINIT_RP_IDLE. This line:

        if (sizeof(outbuf) < 1000) {

... is checking the size of the outbuf object itself, i.e. the size of the type list<vector<char>>, which is a compile-time constant (that happens to be less than 1000). It does not check the number of bytes in the buffer. A proper fix will keep track of the number of bytes currently in the buffer in a member variable. This would mean updating that variable whenever something is added to or removed from the buffer. (It would be possible to calculate the size instead of tracking it in a variable, but since that requires walking through each item in the top-level list it is not efficient).

@davmac314 davmac314 closed this Jul 22, 2023
@davmac314
Copy link
Owner

Btw. If you'd like to implementing as I've suggested please feel free to re-open this PR or create a new one - I'm just closing it for now because it's definitely not the right fix at the moment.

@mobin-2008
Copy link
Collaborator Author

I updated it to disable IN_EVENTS when outbuf vector have >= 1000 members (Is it efficient?) and enable it again when outbuf have < 1000 members. Is it fit our requirements?

@mobin-2008 mobin-2008 force-pushed the control_buffersize branch 2 times, most recently from a9273a0 to 50d64e4 Compare July 23, 2023 17:25
@davmac314
Copy link
Owner

I updated it to disable IN_EVENTS when outbuf vector have >= 1000 members (Is it efficient?) and enable it again when outbuf have < 1000 members. Is it fit our requirements?

outbuf is a list of vectors. See the definition:

    // Buffer for outgoing packets. Each outgoing back is represented as a vector<char>.
    list<vector<char>> outbuf;

Checking its size with outbuf.size() just tells you how many vectors are in the list. It does not tell you how much data is in each of the vectors.

Also, as I mentioned earlier:

A proper fix will keep track of the number of bytes currently in the buffer in a member variable. This would mean updating that variable whenever something is added to or removed from the buffer. (It would be possible to calculate the size instead of tracking it in a variable, but since that requires walking through each item in the top-level list it is not efficient).

@mobin-2008 mobin-2008 force-pushed the control_buffersize branch 2 times, most recently from f818f4a to d89965d Compare July 24, 2023 13:20
Copy link
Owner

@davmac314 davmac314 left a comment

Choose a reason for hiding this comment

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

This is on the right track.

Can you please also use a named constant (a constexpr int at the top of the file is fine) for the buffer watermark value rather than using a literal 1000. Also, 1000 is way too low. Maybe 16kb (16*1024) is reasonable.

src/control.cc Outdated Show resolved Hide resolved
src/control.cc Show resolved Hide resolved
src/includes/control.h Outdated Show resolved Hide resolved
src/control.cc Outdated Show resolved Hide resolved
src/control.cc Outdated Show resolved Hide resolved
@mobin-2008 mobin-2008 force-pushed the control_buffersize branch 2 times, most recently from 72e76f2 to e8f89c5 Compare July 25, 2023 12:56
@mobin-2008 mobin-2008 added C-control Things about custom control protocol of Dinit and removed C-dinitctl Things about dinitctl C-dinit Things about the main parts of dinit labels Jul 25, 2023
src/includes/control.h Outdated Show resolved Hide resolved
src/includes/control.h Outdated Show resolved Hide resolved
Signed-off-by: Mobin "Hojjat" Aydinfar <[email protected]>
Reviewed-by: Davin McCall <EMAIL HIDDEN>
@davmac314 davmac314 merged commit 12e1b7b into davmac314:master Jul 26, 2023
11 checks passed
@mobin-2008 mobin-2008 deleted the control_buffersize branch July 26, 2023 09:33
@mobin-2008
Copy link
Collaborator Author

and It's done! I'm very excited for new 0.17 release and new episode of "Escape from System D" :)

@davmac314
Copy link
Owner

There are a few other changes to go in yet! But yes it is one step closer. 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Importance: Normal C-control Things about custom control protocol of Dinit Enhancement/New Feature Improving things or introduce new feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants