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

Don't modify argv[] in user tools #7760

Merged
merged 1 commit into from Aug 20, 2018

Conversation

DeHackEd
Copy link
Contributor

@DeHackEd DeHackEd commented Aug 1, 2018

argv[] gets modified during string parsing for input arguments. This
is reflected in the live process listing. Don't do that.

Signed-off-by: DHE git@dehacked.net

Motivation and Context

ps output of zfs send currently never includes any @ characters while working because the in-memory commandline has been edited. Other commands have similar missing characters.

Description

alloca() + strcpy() the strings, edit those instead.

How Has This Been Tested?

Various manual runs with valgrind --leak-check=full

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Performance enhancement (non-breaking change which improves efficiency)
  • Code cleanup (non-breaking change which makes code smaller or more readable)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation (a change to man pages or other documentation)

Checklist:

  • My code follows the ZFS on Linux code style requirements.
  • I have updated the documentation accordingly.
  • I have read the contributing document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.
  • All commit messages are properly formatted and contain Signed-off-by.
  • Change has been approved by a ZFS on Linux member.

@ahrens ahrens requested a review from pcd1193182 August 2, 2018 18:16
@behlendorf behlendorf self-requested a review August 13, 2018 15:25
char *fromname = NULL;
char *toname = NULL;
char *dataset = NULL;
Copy link
Contributor

Choose a reason for hiding this comment

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

In order to simply the error handling I think it would be reasonable to put the dataset and fromname on the stack. Since this code always runs in user space we don't have to worry about the kernel's tiny stacks. You can could do something like.

char fromdup[ZFS_MAX_DATASET_NAME_LEN];
...
(void) strlcpy(fromdup, optarg, sizeof (fromdup));
fromname = &fromdup;

Copy link
Contributor Author

@DeHackEd DeHackEd Aug 15, 2018

Choose a reason for hiding this comment

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

What do you think about using alloca(strlen(fromname)) instead for a dynamic allocation still on the stack?

Edit: on second thought, never mind. Your method is used in other places in this function. Best to be consistent.

@@ -4145,16 +4149,17 @@ zfs_do_send(int argc, char **argv)
fromname = frombuf;
}
err = zfs_send_one(zhp, fromname, STDOUT_FILENO, flags);
free(fromname);
Copy link
Contributor

Choose a reason for hiding this comment

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

This could free frombuf which is on the stack. This might be what caused the ZTS failure.

@DeHackEd DeHackEd force-pushed the zfs_send_edits_argv branch 2 times, most recently from 2a87f6a to 0322a85 Compare August 16, 2018 01:06
@DeHackEd
Copy link
Contributor Author

I ended up using something of a mixture of alloca() and fixed stack arrays in an attempt to minimize the number of changes.

Also replaced various instances of argv[0] with dataset for consistency and rebased to master.

@loli10K
Copy link
Contributor

loli10K commented Aug 16, 2018

Motivation and Context
ps output of zfs send currently never includes any @ characters while working because the in-memory commandline has been edited.

This same issue seems to be affecting other zfs sub-commands (e.g. snapshot) and other characters as well (e.g. create, set are missing = in the commandline)

@codecov
Copy link

codecov bot commented Aug 16, 2018

Codecov Report

Merging #7760 into master will decrease coverage by 0.16%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #7760      +/-   ##
==========================================
- Coverage   78.32%   78.15%   -0.17%     
==========================================
  Files         373      373              
  Lines      112791   112805      +14     
==========================================
- Hits        88341    88168     -173     
- Misses      24450    24637     +187
Flag Coverage Δ
#kernel 78.45% <ø> (-0.09%) ⬇️
#user 66.92% <100%> (-0.61%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 802715b...4bdc1ec. Read the comment docs.

@DeHackEd
Copy link
Contributor Author

Interesting. I didn't check that because zfs send is the only command I've noticed since it runs for extended periods.

Maybe main() should just give functions string duplicates of the original argv... :/

@behlendorf
Copy link
Contributor

Maybe main() should just give functions string duplicates of the original argv...

That's not a bad idea. I suspect there's more existing code which makes this assumption and it'd be nice to handle this all in one place. We'd want to update main() in both zfs and zpool.

@DeHackEd
Copy link
Contributor Author

Updated to just duplicate argv[] entirely on the stack and pass the duplicate to all functions instead.

This changes the intent of the commit as a whole while still meeting the same goals.

@DeHackEd
Copy link
Contributor Author

Last round of buildbot failures seem related to a github outage last night. Pushing a noop rebase to make them try again.

@DeHackEd DeHackEd changed the title zfs send: don't modify argv[] Don't modify argv[] in user tools Aug 17, 2018
*/
newargv = alloca((argc + 1) * sizeof (newargv[0]));
for (i = 0; i < argc; i++) {
newargv[i] = alloca(strlen(argv[i] + 1));
Copy link
Contributor

Choose a reason for hiding this comment

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

Hi there! Thanks for working on this change.

Maybe we could change this:

for (i = 0; i < argc; i++) {
	newargv[i] = alloca(strlen(argv[i] + 1));
	strcpy(newargv[i], argv[i]);
}

to this:

for (i = 0; i < argc; i++) {
	newargv[i] = strdupa(argv[i]);
}

(in both cases where it is used)

To be honest though, I'm not sure how to feel about alloca() being
used as it is both platform and compiler dependent. Do we actually
get any wins from using it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Stack allocations are extremely fast don't have to be free()'d at the end of a program since they are effectively freed on return from main(). The alternative with regular strdup() is to call free() afterwards just for the sake of cleanliness. Not that big a deal but we have an alternative that, at least in the context of Linux, works equally as well.

Though platform and compiler dependent, it is well supported on gcc and the Linux man page implies it will be just fine on BSD as well. strdupa is noted as strictly a gcc thing whereas it seems alloca has a somewhat wider range of support. Heck I see an equivalent on MSDN. If alloca is not practical I'd go back to normal strdup/free.

Copy link
Contributor

Choose a reason for hiding this comment

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

I have to admit I'm a bit skittish about using alloca() too. I agree that it should be portable, and it shouldn't cause any issues. But I'd prefer to be conservative and avoid using it unless there's a meaningful win to be had. Let's follow the wise advice in the man page.

The alloca() function is machine- and compiler-dependent. For certain
applications, its use can improve efficiency compared to the use of
malloc(3) plus free(3). In certain cases, it can also simplify memory
deallocation in applications that use longjmp(3) or siglongjmp(3).
Otherwise, its use is discouraged.

Plus this would be the only use of alloca(3) in the entire ZFS code base. Why add another dependency unless we have too.

argv[] gets modified during string parsing for input arguments. This
is reflected in the live process listing. Don't do that.

Signed-off-by: DHE <git@dehacked.net>
@DeHackEd
Copy link
Contributor Author

strdup() it is then.

@behlendorf behlendorf added Status: Accepted Ready to integrate (reviewed, tested) Reviewed labels Aug 19, 2018
@behlendorf behlendorf merged commit edc05fd into openzfs:master Aug 20, 2018
@tonyhutter tonyhutter added this to To do in 0.7.10 Aug 27, 2018
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Aug 28, 2018
argv[] gets modified during string parsing for input arguments. This
is reflected in the live process listing. Don't do that.

Reviewed-by: Serapheim Dimitropoulos <serapheim@delphix.com>
Reviewed-by: loli10K <ezomori.nozomu@gmail.com>
Reviewed-by: Giuseppe Di Natale <guss80@gmail.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: DHE <git@dehacked.net>
Closes openzfs#7760
@tonyhutter tonyhutter moved this from To do to In progress in 0.7.10 Aug 30, 2018
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Aug 30, 2018
argv[] gets modified during string parsing for input arguments. This
is reflected in the live process listing. Don't do that.

Reviewed-by: Serapheim Dimitropoulos <serapheim@delphix.com>
Reviewed-by: loli10K <ezomori.nozomu@gmail.com>
Reviewed-by: Giuseppe Di Natale <guss80@gmail.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: DHE <git@dehacked.net>
Closes openzfs#7760
@tonyhutter tonyhutter moved this from In progress to Done in 0.7.10 Aug 30, 2018
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Sep 5, 2018
argv[] gets modified during string parsing for input arguments. This
is reflected in the live process listing. Don't do that.

Reviewed-by: Serapheim Dimitropoulos <serapheim@delphix.com>
Reviewed-by: loli10K <ezomori.nozomu@gmail.com>
Reviewed-by: Giuseppe Di Natale <guss80@gmail.com>
Reviewed-by: George Melikov <mail@gmelikov.ru>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: DHE <git@dehacked.net>
Closes openzfs#7760
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Accepted Ready to integrate (reviewed, tested)
Projects
No open projects
0.7.10
  
Done
Development

Successfully merging this pull request may close these issues.

None yet

6 participants