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

replaced mktemp with tempfile for supress warning mktemp is dangerous #198

Merged
merged 1 commit into from May 29, 2018

Conversation

@akoserwal
Copy link

akoserwal commented May 20, 2018

No description provided.

@akoserwal
Copy link
Author

akoserwal commented May 20, 2018

#11

//avoid deleting temp director automatically
let _tmp_path = dir.into_path();

let mut _tmp_file = tempfile_in(&_tmp_path).unwrap();

This comment has been minimized.

@dlrobertson

dlrobertson May 22, 2018

Collaborator

Are _tmp_path and _tmp_file needed? also dir doesn't live long enough. TempDir implements Drop, so it will be closed at the end of this function.

This comment has been minimized.

@akoserwal

akoserwal May 22, 2018

Author

yes, test run got stuck. If I remove _tmp_path and _tmp_file. tempdir is getting dropped before socket bind operation.

test platform::test::sender_transfer ... ok
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: UnixError(2)', libcore/result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.
test platform::test::cross_process ... test platform::test::cross_process has been running for over 60 seconds
test platform::test::cross_process_sender_transfer ... test platform::test::cross_process_sender_transfer has been running for over 60 seconds

Same case when I remove _tmp_path. and use either File::create or tempfile_in using tempDir path.

   let mut _tmp_file = tempfile_in(&dir).unwrap(); ```

This comment has been minimized.

@dlrobertson

dlrobertson May 22, 2018

Collaborator

If I remove _tmp_path and _tmp_file. tempdir is getting dropped before socket bind operation.

Can't you add dir to the OsIpcOneShotServer so it doesn't get dropped.

@@ -31,6 +31,8 @@ use std::time::UNIX_EPOCH;
use std::thread;
use mio::unix::EventedFd;
use mio::{Poll, Token, Events, Ready, PollOpt};
use tempfile::{TempDir};

This comment has been minimized.

@dlrobertson

dlrobertson May 22, 2018

Collaborator

no need for braces or empty line afterwards.

This comment has been minimized.

@@ -577,6 +579,7 @@ impl OsOpaqueIpcChannel {

pub struct OsIpcOneShotServer {
fd: c_int,
_dir:TempDir,

This comment has been minimized.

@dlrobertson

dlrobertson May 22, 2018

Collaborator

might want to add a comment as to why this is needed.

@antrik
Copy link
Contributor

antrik commented May 23, 2018

@akoserwal you seem to have two PRs open for the same thing? Unless I'm missing something, please close one of them...

Copy link
Contributor

antrik left a comment

To be honest, the approach using a dedicated directory seems a bit circumspect to me, as opposed to simply generating a more unique/unguessable name, using something like libc::tmpnam()...

(Are symlink attacks even possible against sockets?)

On the other hand, this approach allows using the existing crate, which also takes care of cleanup (otherwise we would have to add manual handling for that: the original implementation doesn't do it at all!) -- so all in all it's a good thing I guess :-)

I found a couple of issues with your code though...

BTW, you should probably put closes https://github.com/servo/ipc-channel/issues/11 somewhere in your commit message, so GitHub will automatically close the issue when the pull request is merged.

@@ -31,6 +31,8 @@ use std::time::UNIX_EPOCH;
use std::thread;
use mio::unix::EventedFd;
use mio::{Poll, Token, Events, Ready, PollOpt};
use tempfile::TempDir;


This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

Remove the spurious extra blank line you added here.

@@ -575,8 +577,11 @@ impl OsOpaqueIpcChannel {
}
}

//_dir: keeps track of temp directory required when the socket is created and drops temp directory automatically.

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

The comment should go directly in front of the field it pertains to, not in front of the containing structure. (Maybe separated from the previous field by a blank line, but with no blank line between the comment and the field it pertains to.)

Also, the comment is a bit unclear IMHO... I'd suggest something like:

// Object representing the temporary directory the socket was created in.
// The directory is automatically deleted (along with the socket inside it)
// when this field is dropped.

Might also be good to rename the field itself to _temp_dir?

pub struct OsIpcOneShotServer {
fd: c_int,
_dir:TempDir,

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

Missing a blank after the :.

@@ -593,13 +598,15 @@ impl OsIpcOneShotServer {
unsafe {
let fd = libc::socket(libc::AF_UNIX, SOCK_SEQPACKET, 0);
let mut path: Vec<u8>;
let dir = TempDir::new().unwrap();
let dir_path = dir.path().join("rust-ipc-socket");

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

dir_path is a confusing name: it sounds like it was the path of the temporary directory... Rename it to something like socket_path I'd say -- or maybe just path? (Note that the other path variable should be gone once you address my remark about back-and-forth conversion below...)

@@ -593,13 +598,15 @@ impl OsIpcOneShotServer {
unsafe {
let fd = libc::socket(libc::AF_UNIX, SOCK_SEQPACKET, 0);
let mut path: Vec<u8>;
let dir = TempDir::new().unwrap();
let dir_path = dir.path().join("rust-ipc-socket");

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

This blank line has trailing white space. Git should have warned you about that while committing...

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

Still has the trailing white space...

You can see the extra white space in the GitHub diff if you select the line; and locally, git diff marks this very visibly. (Unless diff colouring is disabled for some reason...)

Ideally, you should configure your text editor to show trailing white space, so you can avoid such mistakes in the first place.

That said, I don't think the blank line here is actually useful any more after the latest changes...

let path_string = CString::new(dir_path.to_str().unwrap()).unwrap();
path = path_string.as_bytes_with_nul().iter().cloned().collect();


This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

More trailing white space; and (at least) one blank line too much...


let path_string = CString::new(dir_path.to_str().unwrap()).unwrap();
path = path_string.as_bytes_with_nul().iter().cloned().collect();

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

The complex cloning and back-and-forth conversion was only necessary because mktemp() mutates the string. You can use a much simpler approach now, like in connect().

@@ -616,7 +623,7 @@ impl OsIpcOneShotServer {
}

Ok((OsIpcOneShotServer {
fd: fd,
fd: fd, _dir: dir,

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

The second field initialiser goes on a separate line.

@@ -593,13 +598,15 @@ impl OsIpcOneShotServer {
unsafe {
let fd = libc::socket(libc::AF_UNIX, SOCK_SEQPACKET, 0);
let mut path: Vec<u8>;
let dir = TempDir::new().unwrap();

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

Please use tempfile::Builder (https://docs.rs/tempfile/3.0.2/tempfile/struct.Builder.html), to get a meaningful directory name. (The actual file name can then be shortened to just "socket" I guess.)

@@ -593,13 +598,15 @@ impl OsIpcOneShotServer {
unsafe {
let fd = libc::socket(libc::AF_UNIX, SOCK_SEQPACKET, 0);
let mut path: Vec<u8>;
let dir = TempDir::new().unwrap();
let dir_path = dir.path().join("rust-ipc-socket");

loop {

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

With the new approach, you can drop the loop and the EINVAL handling I believe: AIUI we only needed to retry, because using mktemp() is not atomic. (Someone else might have taken the name between our mktemp() and bind() calls.) tempfile doesn't have that issue.

Might be prudent though to do this change in a separate commit, just in case... (While all your other changes of course will have to be squashed into one before this can be merged.)

let dir_path = dir.path().join("rust-ipc-socket");
let _temp_dir = Builder::new()
.tempdir()
.unwrap();

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

A few nitpicks here: the local temp_dir variable doesn't need to start with _, since it's actually used. (Unlike the _temp_dir field in OsIpcOneShotServer.)

There should be only one blank after the =. (You have two...)

The chained calls easily fit on one line (and pose no readability issues) -- no need to use extra lines for them.

@@ -31,8 +31,7 @@ use std::time::UNIX_EPOCH;
use std::thread;
use mio::unix::EventedFd;
use mio::{Poll, Token, Events, Ready, PollOpt};
use tempfile::TempDir;

use tempfile::{Builder,TempDir};

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

Please add a blank after the ,.

Sorry if these formatting issues sound pedantic -- but it's important to stick with the conventions, as otherwise people will always stumble while reading the code...

This comment has been minimized.

@akoserwal

akoserwal May 24, 2018

Author

@antrik: No problem, it's imp & I appreciate it. thanks

@@ -593,13 +598,15 @@ impl OsIpcOneShotServer {
unsafe {
let fd = libc::socket(libc::AF_UNIX, SOCK_SEQPACKET, 0);
let mut path: Vec<u8>;
let dir = TempDir::new().unwrap();
let dir_path = dir.path().join("rust-ipc-socket");

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

Still has the trailing white space...

You can see the extra white space in the GitHub diff if you select the line; and locally, git diff marks this very visibly. (Unless diff colouring is disabled for some reason...)

Ideally, you should configure your text editor to show trailing white space, so you can avoid such mistakes in the first place.

That said, I don't think the blank line here is actually useful any more after the latest changes...

}, String::from_utf8(CStr::from_ptr(path.as_ptr() as
fd: fd,
_temp_dir: _temp_dir,
}, String::from_utf8(CStr::from_ptr(path_string.as_ptr() as
*const c_char).to_bytes().to_owned()).unwrap()))

This comment has been minimized.

@antrik

antrik May 23, 2018

Contributor

This complicated conversion is not necessary any more: you actually already have the final Rust string after the socket_path.to_str().unwrap() (before converting it to CString) -- you just need to add a .to_owned(), and save it in another temporary variable. (Or even chain this conversion right in the assignment of socket_path.)

}
let temp_dir = Builder::new().tempdir().unwrap();
let socket_path = temp_dir.path().join("socket");
let path_string = socket_path.to_str().to_owned().unwrap();

This comment has been minimized.

@antrik

antrik May 24, 2018

Contributor

to_owned() in this place is useless. My suggestion was to add it after the unwrap(), to convert the resulting &str into a String. (Maybe I should have said to_string() instead to make it clearer... Not sure whether there is consensus nowadays which one is preferable.)

Though doing the to_string() conversion only while returning the result, as you did, is fine too -- i.e. you don't need the extra to_owned() or to_string() here at all.

This comment has been minimized.

@akoserwal

akoserwal May 24, 2018

Author

So, it will be like

   let path_string = CString::new(socket_path.to_str().unwrap()).unwrap();

This comment has been minimized.

@antrik

antrik May 27, 2018

Contributor

No, that's what you had before... Your last version was actually closer.

Sorry if I'm not making myself clear. I was thinking of something like

    let name = socket_path.to_str().unwrap();
    let name_ffi = CString::new(name).unwrap();

(And later return name.to_string().)

Maybe you could even do the CString conversion directly in the new_sockaddr_un() call, since you do not need the value of name_ffi anywhere else...

This comment has been minimized.

@akoserwal

akoserwal May 27, 2018

Author

@antrik : thank you so much for keeping patience with me.

if errno.0 != libc::EINVAL {
return Err(errno)
}
let (sockaddr, len) = new_sockaddr_un(path_string.as_ptr() as *const c_char);

This comment has been minimized.

@antrik

antrik May 24, 2018

Contributor

There was a misunderstanding here: you still do need to convert the string to a CString before passing it to new_sockaddr_un. My point was just that you can grab the string to be returned at the end before doing the conversion to CString, rather than converting the CString back to a standard String...

@antrik
Copy link
Contributor

antrik commented May 24, 2018

BTW, I said to add closes https://github.com/servo/ipc-channel/issues/11, rather than just closes #11, for a reason: while it looks the same in the GitHub interface, it's not the same when looking at the commit message through other means...

if libc::bind(fd, &sockaddr as *const _ as *const sockaddr, len as socklen_t) == 0 {
break
}
let temp_dir = Builder::new().tempdir().unwrap();

This comment has been minimized.

@antrik

antrik May 27, 2018

Contributor

I just noticed there is a second blank after the = here as well...

@@ -617,7 +613,8 @@ impl OsIpcOneShotServer {

Ok((OsIpcOneShotServer {
fd: fd,
}, String::from_utf8(CStr::from_ptr(path.as_ptr() as
_temp_dir: temp_dir,
}, String::from_utf8(CStr::from_ptr(path_string.as_ptr() as
*const c_char).to_bytes().to_owned()).unwrap()))

This comment has been minimized.

@antrik

antrik May 27, 2018

Contributor

You didn't remove the back-and-forth conversion here -- but that was the whole point of shuffling around the other conversions/bindings above...

This comment has been minimized.

@akoserwal

akoserwal May 28, 2018

Author

So, this will be just
path_string.to_string()
right?

This comment has been minimized.

@antrik

antrik May 28, 2018

Contributor

Indeed :-)

This comment has been minimized.

@antrik
Copy link
Contributor

antrik commented May 28, 2018

Looks good now :-)

Please squash the commits into one, and give it a nice commit message, describing what you did and why.

(The title line could read something like "unix: Use tempfile crate for creating socket location". How much you write in the long description, depends on how ambitious you feel about this -- I for my part would mention getting rid of mktemp() for security concerns and the associated linker warning; briefly explain how we instead safely create an exclusive temporary directory to put the socket in; and how we do not need the loop any more. Not forgetting to point out that as an extra bonus, this takes care of cleanup, since tempdir does that automatically... And of course closing the issue.)

Just in case you are unsure how to a good commit message could look like, I suggest reading through a bunch of existing commit messages for inspiration :-)

Removed mktemp() for creating the temporary location for the socket creation. Addressing
the security concern of easy guessable name & race condition required the loop for checking
whether the file exists or not.

Used tempfile crate, which provides builder pattern for safely creating an exclusive
temporary location and take cares of dropping it automatically along with socket in it.

closes #11
@akoserwal akoserwal force-pushed the akoserwal:fix-tempdir-repace-mktemp branch from 556d25a to 8d72a95 May 29, 2018
@antrik
Copy link
Contributor

antrik commented May 29, 2018

Oh, you already updated it :-)

(I didn't see it earlier, since GitHub doesn't notify on rebases...)

@bors-servo r+

@bors-servo
Copy link
Contributor

bors-servo commented May 29, 2018

📌 Commit 8d72a95 has been approved by antrik

@bors-servo
Copy link
Contributor

bors-servo commented May 29, 2018

Testing commit 8d72a95 with merge f2723d0...

bors-servo added a commit that referenced this pull request May 29, 2018
replaced mktemp with tempfile for supress warning mktemp is dangerous
@bors-servo
Copy link
Contributor

bors-servo commented May 29, 2018

💔 Test failed - status-travis

@bors-servo
Copy link
Contributor

bors-servo commented May 29, 2018

☀️ Test successful - status-appveyor, status-travis
Approved by: antrik
Pushing f2723d0 to master...

@bors-servo bors-servo merged commit 8d72a95 into servo:master May 29, 2018
3 checks passed
3 checks passed
continuous-integration/appveyor/pr AppVeyor build succeeded
Details
continuous-integration/travis-ci/pr The Travis CI build passed
Details
homu Test successful
Details
@akoserwal
Copy link
Author

akoserwal commented May 29, 2018

@antrik @dlrobertson : thank you, great learning experience :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

5 participants
You can’t perform that action at this time.