Skip to content

Mark nix::sys::ptrace::ptrace as unsafe, add safe variants of some routines #709

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

Merged
merged 14 commits into from
Aug 11, 2017

Conversation

marmistrz
Copy link
Contributor

@marmistrz marmistrz commented Jul 26, 2017

These include:

  • PTRACE_TRACEME
  • PTRACE_CONT
  • PTRACE_ATTACH
  • PTRACE_SYSCALL

This is a part of #666, which is being split up into a couple smaller PRs.

…routines.

These include:
* PTRACE_TRACEME
* PTRACE_CONT
* PTRACE_ATTACH
* PTRACE_SYSCALL
@marmistrz marmistrz changed the title Mark nix::sys::ptrace::ptrace as unsafe, add safe variants of source routines Mark nix::sys::ptrace::ptrace as unsafe, add safe variants of some routines Jul 26, 2017
}

/// Makes the `PTRACE_CONT` request to ptrace
pub fn cont(pid: Pid) -> Result<()> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Call this "continue" instead.

And provide better docs here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wanted to keep consistent with the C API: PTRACE_TRACEME => ptrace::traceme, so PTRACE_CONT => ptrace::cont

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand why it's this way, but nix does renaming as is appropriate to make things more clear, and I think this is one of those times. So let's change it to "continue"

Copy link
Contributor Author

@marmistrz marmistrz Jul 27, 2017

Choose a reason for hiding this comment

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

Sorry, continue will not work:

error: expected identifier, found keyword `continue`
   --> src/sys/ptrace.rs:193:8
    |
193 | pub fn continue(pid: Pid) -> Result<()> {
    |        ^^^^^^^^


Leaving this as it is.

@@ -70,7 +70,7 @@ mod ffi {

/// Performs a ptrace request. If the request in question is provided by a specialised function
/// this function will return an unsupported operation error.
pub fn ptrace(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
pub unsafe fn ptrace(request: ptrace::PtraceRequest, pid: Pid, addr: *mut c_void, data: *mut c_void) -> Result<c_long> {
Copy link
Contributor

Choose a reason for hiding this comment

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

This needs to be expanded to report UnsupportedOperation for all 4 added specialized functions.

Also, what are the specific usecases of ptrace that will generate unsafety as Rust defines it (crashing isn't necessarily unsafe)? Since you pulled this out of another PR, I don't know where that discussion went.

Copy link
Contributor Author

@marmistrz marmistrz Jul 26, 2017

Choose a reason for hiding this comment

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

And thus break the specialized functions: ptrace::syscall calls ptrace::ptrace with request=PTRACE_SYSCALL.

ptrace can dereference arbitrary pointer in the child process memory.

}
}

/// Makes the `PTRACE_SYSCALL` request to ptrace
Copy link
Contributor

Choose a reason for hiding this comment

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

This comment should be more descriptive on the first sentence and include a really good extended description explaining what it does.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should I copy-paste the ptrace manual? I thought that the user should be familiar with what ptrace does.

Copy link
Contributor

Choose a reason for hiding this comment

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

Not the whole thing, but providing a little more detail would be nice. nix documentation can also be used as a form of discovery for users who aren't familiar with the POSIX APIs. While I don't expect nix to replace the man pages or other sources of documentation, it should allow people unfamiliar with the concepts to understand a little of the functionality.

}
}

/// Makes the `PTRACE_ATTACH` request to ptrace
Copy link
Contributor

Choose a reason for hiding this comment

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

Better docs, like above.

@@ -140,3 +140,51 @@ pub fn setsiginfo(pid: Pid, sig: &siginfo_t) -> Result<()> {
Err(e) => Err(e),
}
}

/// Sets the process as traceable with `PTRACE_TRACEME`
Copy link
Contributor

Choose a reason for hiding this comment

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

Needs an extended description that elaborates a bit here.

@Susurrus
Copy link
Contributor

Please don't break up PRs unless we ask you too as it makes it hard for us to follow the discussion (see my comments about safety). It also generates a lot of email traffic for a lot of us.

@marmistrz
Copy link
Contributor Author

Well, the problem is that #666 has gotten far too big and complex and if I keep it in one chunk, we won't merge it for another two weeks. And I have trouble isolating the cause of tests failing, especially that they succeed on my machine.

It'll be much easier to ditch #666 (and close it when all the related changes are in) and successfully merge the changes by chunks.

@Susurrus
Copy link
Contributor

@marmistrz Let's refocus #666 on just adding the register ptrace wrapper since that's what most of it is about. Closing it we lose the history of the discussion, which has mostly been around that single feature, so let's keep it around.

@marmistrz
Copy link
Contributor Author

marmistrz commented Jul 27, 2017

I'm wondering about the ptrace::cont. From manpage:

Restart the stopped tracee process.  If data is nonzero, it is interpreted as the number of a signal to be delivered to the tracee; otherwise, no signal is delivered.  Thus, for example,  the
              tracer can control whether a signal sent to the tracee is delivered or not.  (addr is ignored.)

Currently ptrace::cont uses data = 0, so delivers no signal. We could solve it in two ways:

  1. Change the signature to
pub fn cont(pid: Pid, sig: Option<Signal>) -> Result<()> {
  1. Create two functions:
pub fn cont(pid: Pid) -> Result<()> {
pub fn cont_signal(pid: Pid, sig: Signal) -> Result<()> {

I really think about settling with solution 2 because the most common use case is not to deliver any signal. What do you think?

@Susurrus
Copy link
Contributor

Susurrus commented Jul 27, 2017

Let's use:

pub fn cont<T: Into<Option<Signal>>>(pid: Pid, sig: T) -> Result<()>;

I don't see the need for two functions just because it's too hard to add a None argument. It's a goal of nix to stay as close as is reasonable to the C APIs.

@marmistrz
Copy link
Contributor Author

It looks like we've got some problems with qemu. Should I disable the test on these arm/ppc?

@Susurrus
Copy link
Contributor

@marmistrz If you think it's a QEMU failure, just document it and disable them for it.

@marmistrz
Copy link
Contributor Author

marmistrz commented Aug 1, 2017

The tests have succeeded but Github still shows them as not yet finished: https://travis-ci.org/nix-rust/nix/builds/259406655?utm_source=github_status&utm_medium=notification

@@ -58,6 +58,7 @@ fn test_ptrace_cont() {

// FIXME: qemu-user doesn't implement ptrace on all arches and gives ENOSYS then.
// use it to filter out the affected platforms
Copy link
Contributor

Choose a reason for hiding this comment

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

Both of these comments could use proper punctuation and capitalization.

@marmistrz
Copy link
Contributor Author

Is it ok now?

@Susurrus
Copy link
Contributor

Susurrus commented Aug 3, 2017

@marmistrz Not yet. You haven't expanded the list of ptrace operations that return and Unsupported error. This is also missing a Changed entry in the CHANGELOG. Should be something like "Using ptrace() with PTRACE_TRACEME, ... is no longer supported. Instead use the specialized functions traceme(), ..."

@marmistrz
Copy link
Contributor Author

marmistrz commented Aug 3, 2017

@Susurrus, but this will break traceme! User calls traceme, which internally calls ptrace(PTRACE_TRACEME, and whoops!

And ptrace is a very convenient function for internal use by the library

@Susurrus
Copy link
Contributor

Susurrus commented Aug 3, 2017

@marmistrz You're correct, you should change these functions to use libc::ptrace or a helper function. This is how the existing specialized wrapper functions work.

@marmistrz
Copy link
Contributor Author

marmistrz commented Aug 3, 2017

So you're asking me to add 4 more matches now, 6 more in #666... That's poor for readability, maintanance, that's ~3 rows of listing enum variants! And there are about 30 ptrace routines in total!

Man, it's breaking other people's code without a single, smallest warning, without a single compile-time message. If a program starts tracing another using PTRACE_SEIZE, it may not realize something's going on until the program enters an unfortunate branch!! And it's so easy to cargo update.

Let's just mark it as deprecated:

#[deprecated(since="...", note="please use specialized wrappers instead or contribute one if such doesn't exist")]

@Susurrus
Copy link
Contributor

Susurrus commented Aug 3, 2017

Yes I am. This isn't that onerous and is not a large maintenance concern. Eventually ptrace() will be completely removed from our external API and only the specialized variants will be supported. Until then, we'll be making each variant return Unsupported errors as they're implemented. #deprecated doesn't quite have the right semantics, since the function as a whole isn't deprecated, just some variants of it.

As to the breaking people's code piece, yes we are. Every release will likely have breaking changes as we improve or stabilize our APIs. nix is pre-1.0 for a reason and breakages should be expected. You should also be wary of cargo update if you use any pre-1.0 crates for exactly this reason.

@marmistrz
Copy link
Contributor Author

@Susurrus It's one thing to break the API so it doesn't compile and another to introduce runtime error in the most unexpected place. API changes should be clear from the developers perspective and this, in any case, is not. And I can't stress how sneaky the change is - you may realized it weeks after updating the dependency because you simply used the supported operations.

It's just as though Rust decided that try! will panic instead of returning a result, and you've never realized it because you never had any errors before. Changing the interface is one thing, changing the semantics - another.

Moreover, Rust favors compile-time checking and falls back to runtime errors only when it's absolutely necessary.

Deprecating a 1/10 of an API because we have a 1/10 of a new API is just insane. It's just as though you had to use methods .minus(), .multiply() to multiply complex numbers but .add() threw a runtime error out of nowhere because you should a + operator.

I suggest we annotate the current state of the API in the documentation. The general ptrace function should be simply removed when all the wrappers are ready, and since we're 0.x - we can simply remove it.

@Susurrus
Copy link
Contributor

Susurrus commented Aug 9, 2017

@marmistrz I understand your viewpoint on this, but I don't see it as as big of an issue as you suggest.

That being said, I think we should go ahead and add #[deprecated(since="0.10.0", note="usages of ptrace() should be replaced with the specialized helper functions instead")].

Additionally I'm fine with you not expanding the UnsupportedOperation part of ptrace().

@marmistrz
Copy link
Contributor Author

marmistrz commented Aug 10, 2017

It's great we've found a compromise! I think we should document the internal functions ptrace_other and ptrace_peek (possibly in a separate pull request)

As far as I can see, ptrace_other takes care of those routines which do not return anything interesting and ptrace_peek - those who do (so peeks). But why does ptrace_peek match against Err(Error::Sys(Errno::UnknownErrno))?

I think the name ptrace_other could be clearer. I had an idea to create a second function, named, for example, fn ptrace_noretval(...) -> Result<()>, which would save us the .map(|_| ()) in the specialized wrappers. And remove ptrace_other just when we decide to remove ptrace. What do you think?

@Susurrus
Copy link
Contributor

@marmistrz I think you're on the right track for cleaning up these helper functions. I don't think you need feedback from me, so why don't you go ahead and clean those up. You can put it as the first commit in this series or file a new PR, whatever you want.

As to why UnknownErrno is checked for, I'm not certain. It was there in the first implementation added in a0fc607.

@marmistrz
Copy link
Contributor Author

Sure. I'll do this in a separate PR. Let's finally have it merged :)

@Susurrus
Copy link
Contributor

Thanks for your hard work pushing on this @marmistrz! Love that we have more tests for this too.

bors r+

bors bot added a commit that referenced this pull request Aug 11, 2017
709: Mark nix::sys::ptrace::ptrace as unsafe, add safe variants of some routines r=Susurrus

These include:
* PTRACE_TRACEME
* PTRACE_CONT
* PTRACE_ATTACH
* PTRACE_SYSCALL

This is a part of #666, which is being split up into a couple smaller PRs.
@bors
Copy link
Contributor

bors bot commented Aug 11, 2017

@bors bors bot merged commit abcec0f into nix-rust:master Aug 11, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants