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

Pr/fix strings #567

Merged
merged 28 commits into from Jan 7, 2018
Merged

Pr/fix strings #567

merged 28 commits into from Jan 7, 2018

Conversation

uli42
Copy link
Member

@uli42 uli42 commented Nov 24, 2017

Fix two possible buffer overflows, one memory leak and some minor string stuff.

@uli42 uli42 requested a review from Ionic November 24, 2017 00:39
@@ -1907,8 +1905,8 @@ Bool nxagentMakeIcon(Display *display, Pixmap *nxIcon, Pixmap *nxMask)
agentIconData=nxagentIconData;
}


snprintf(default_path, PATH_MAX-1, "/usr/NX/share/images/%s", agent_icon_name);
/* FIXME: use a compile tiem define here, /usr/NX is a nomachine path */
Copy link
Member

Choose a reason for hiding this comment

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

s/tiem/time/

Copy link
Member

@sunweaver sunweaver left a comment

Choose a reason for hiding this comment

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

I went over this quickly. Need to take a second glance once we have merged the other PRs.

@uli42 uli42 force-pushed the pr/fix_strings branch 2 times, most recently from 993fcad to b9d1443 Compare December 5, 2017 20:40
@uli42
Copy link
Member Author

uli42 commented Dec 5, 2017

fixed typo and rebased

@@ -53,7 +53,7 @@ struct UserGeometry{
extern Bool nxagentUseNXTrans;

extern char nxagentSessionId[];
extern char nxagentDisplayName[];
extern char nxagentDisplayName[1024];
Copy link
Member

Choose a reason for hiding this comment

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

Don't do this. The size given here is merely a hint and will be ignored.

Even worse, it's allowed for the definition in a source file to deviate from that declaration.

We really should use SIZE macros for these arrays.

Args.h:

char nxagentDisplayName[];
#define NXAGENTDISPLAYNAMELENGTH 1024;

Args.c:

char nxagentDisplayName[NXAGENTDISPLAYNAMELENGTH];

An alternative way would be define size variables:

Args.h:

char nxagentDisplayName[];
size_t nxagentDisplayNameLength;

Args.c:

char nxagentDisplayName[1024];
size_t nxagentDisplayNameLength = (sizeof(nxagentDisplayName) / sizeof(*nxagentDisplayName));

The drawback is that this alternative will only work for fixed-size arrays, but not for pure pointers.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm, I had to add the size here because otherwise the sizeof would fail if used in sources other than Args.c. So I am wondering if you are really right about the "only a hint" stuff.

Generally I want to get rid of all those limits as they are only artificial. So I will change the code one day to not use fixed array.

Copy link
Member

Choose a reason for hiding this comment

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

Looks like I've been wrong - T foo[]; declares an incomplete type that must be properly defined at a later point (unless the code in question does not need storage information).

Multiple declarations for he same object with different sizes lead a compile error in recent versions of both clang and gcc.

There is a special case that I confused this with: within parameters declared like this, the size is merely a hint:

b.c: In function ‘get_size_2’:
b.c:9:18: warning: ‘sizeof’ on array function parameter ‘arg’ will return size of ‘char *’ [-Wsizeof-array-argument]
   return (sizeof (arg));
                  ^
b.c:8:25: note: declared here
 size_t get_size_2 (char arg[6]) {
                         ^~~

(the array I pass in actually is `char foo[5]` - and that works)

For now, I'd really use a macro.

Bounding even pure pointers would also be a good idea, even if that adds an artificial limit. We can certainly raise this limit, but not doing it at all is dangerous in case the input data is invalid.

Copy link
Member Author

Choose a reason for hiding this comment

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

ok, I have added macros (for now). And fixed two bugs in nxagentGetDialogName: the wrong string was terminated and there where no length checks.

fprintf(stderr, "Error: Path too long.\n");
return NULL;
}

strcpy(singlePath, path);

breakLoop = 1;
Copy link
Member

Choose a reason for hiding this comment

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

With these changes, it doesn't make sense to keep breakLoop around. Drop it.

Copy link
Member Author

Choose a reason for hiding this comment

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

must check

Copy link
Member

Choose a reason for hiding this comment

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

Ping.

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think so. breakLoop indicates that we have processed the last path from the env variable. If we have checked that one (and found no file in that path we still need to terminate the loop).

I have improved the code:

  • use True/False
  • move variables to inner scope where possible
  • add comments
  • strip all trailing slashes, not only the last one
  • pass down the size of the return_path array


snprintf(default_path, PATH_MAX-1, "/usr/NX/share/images/%s", agent_icon_name);
/* FIXME: use a compile time define here, /usr/NX is a nomachine path */
snprintf(default_path, sizeof(default_path), "/usr/NX/share/images/%s", agent_icon_name);
Copy link
Member

Choose a reason for hiding this comment

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

I agree, but wonder why the original code used PATH_MAX - 1. Probably didn't know that snprintf includes the terminating 0 character in the length and only writes n - 1 elements to the target buffer (+ terminating 0). strncpy is different in this regard. They probably got confused by that...

Copy link
Member Author

Choose a reason for hiding this comment

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

that's what I thought, too.

@@ -1406,9 +1406,10 @@ Bool nxagentDisconnectAllFonts()

static Bool nxagentGetFontServerPath(char * fontServerPath)
{
char path[256];
/* ensure path is not longer that fontServerPath) */
char path[sizeof(fontServerPath)];
Copy link
Member

Choose a reason for hiding this comment

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

Can't do this. fontServerPath is a pure pointer. We cannot use sizeof() here.

Copy link
Member Author

Choose a reason for hiding this comment

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

you are right, will fix that.

FILE *keyboard_file;
if (keyboard_file_path == NULL)

if ((asprintf(&keyboard_file_path, "%s/keyboard", sessionpath) == -1))
Copy link
Member

Choose a reason for hiding this comment

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

Nope, we can't use asprintf yet. It's not your fault, but really mine since I didn't notice this error when reviewing some of @sunweaver's commits that used asprintf.

It doesn't mean that you have to change the code - but this PR will be blocked until I've backported os/xprintf.c so that asprintf is available across platforms.

Copy link
Member Author

Choose a reason for hiding this comment

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

what platforms are lacking it?

" These functions are GNU extensions, not in C or POSIX. They are also
available under *BSD. The FreeBSD implementation sets strp to NULL
on error."

Copy link
Member Author

Choose a reason for hiding this comment

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

By the way: backporting asprintf doesn't sound like fun: http://insanecoding.blogspot.de/2014/06/memory-management-in-c-and-auto.html

Copy link
Member

Choose a reason for hiding this comment

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

I don't know what platforms are not providing it exactly, but there certainly seem to be X.Org-supported ones that don't.

Backporting asprintf is really easy! But only because X.Org already did it. I'll take a stab at it tomorrow (or at a later time) after I went through the other open PRs.

Copy link
Member

Choose a reason for hiding this comment

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

asprintf comment obsolete.

{
FatalError("nxagentKeycodeConversionSetup: malloc failed.");
free(sessionpath);
Copy link
Member

Choose a reason for hiding this comment

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

Okay, but FatalErrror is noreturn anyway. At this point a memory leak won't hurt. Still good to free the memory.

@@ -308,7 +305,7 @@ void nxagentLaunchDialog(DialogType dialogType)
DECODE_DIALOG_TYPE(dialogType), *pid, dialogDisplay);
#endif

*dialogDisplay = '\0';
dialogDisplay[0] = '\0';
Copy link
Member

Choose a reason for hiding this comment

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

Functionally equivalent. Just a comment.

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah, but better to read IMHO.

@@ -112,7 +112,7 @@ static const char *_NXGetFontPath(const char *path)
* Check the environment only once.
*/

if (*_NXFontPath != '\0')
if (_NXFontPath[0] != '\0')
Copy link
Member

Choose a reason for hiding this comment

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

Functionally equivalent. Just a comment.

@uli42 uli42 force-pushed the pr/fix_strings branch 2 times, most recently from 80a4625 to e5c9a65 Compare December 11, 2017 22:09
*(fontServerPath + *path) = '\0';
if (len)
{
strncpy(fontServerPath, path + 1, len);
Copy link
Member

Choose a reason for hiding this comment

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

Might as well use snprintf() here.

Copy link
Member Author

@uli42 uli42 Jan 2, 2018

Choose a reason for hiding this comment

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

will leave that for now have changed it to that we now the size here; also added a MIN() guard

FILE *keyboard_file;
if (keyboard_file_path == NULL)

if ((asprintf(&keyboard_file_path, "%s/keyboard", sessionpath) == -1))
Copy link
Member

Choose a reason for hiding this comment

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

asprintf comment obsolete.

path = end + 1;
continue;
}

strncpy(singlePath, path, (unsigned long)(end - path));
Copy link
Member

Choose a reason for hiding this comment

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

snprintf to drop the NULL setting.

Copy link
Member Author

Choose a reason for hiding this comment

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

done

fprintf(stderr, "Error: Path too long.\n");
return NULL;
}

strcpy(singlePath, path);

breakLoop = 1;
Copy link
Member

Choose a reason for hiding this comment

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

Ping.

@uli42 uli42 force-pushed the pr/fix_strings branch 2 times, most recently from d971931 to 1a36181 Compare January 2, 2018 20:03
@uli42
Copy link
Member Author

uli42 commented Jan 2, 2018

@Ionic can you please re-check?

@uli42 uli42 force-pushed the pr/fix_strings branch 7 times, most recently from c60fcc3 to c96c7c0 Compare January 3, 2018 01:35
}

/* append slash and icon name */
if (strlen(singlePath) + strlen(iconName) + 1 < PATH_MAX)
{
strncat(singlePath, slash, 1);
strcat(singlePath, iconName);
Copy link
Member

Choose a reason for hiding this comment

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

Hello, I'm Shlemiel the Painter!

How about...

  snprintf(singlePath + strlen(singlePath), sizeof(singlePath), "%.1s%s", slash, iconName);

?

Copy link
Member Author

@uli42 uli42 Jan 3, 2018

Choose a reason for hiding this comment

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

Ok, accepted, but the .1 is not needed because slash is only one char.

Copy link
Member

Choose a reason for hiding this comment

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

Okay, I thought thought it might be a good idea to limit reading data out of slash to one character, just in case.

}

/* append slash and icon name */
if (strlen(singlePath) + strlen(iconName) + 1 < PATH_MAX)
Copy link
Member

Choose a reason for hiding this comment

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

Replace PATH_MAX here with sizeof(singlePath)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Can do that, but weren't you the one that didn't like that? ;-)

Copy link
Member Author

Choose a reason for hiding this comment

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

done

Copy link
Member

Choose a reason for hiding this comment

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

For global, fixed-size arrays yes. For local ones using a special macro doesn't make a lot of sense, though. PATH_MAX is a too generic one.

@@ -118,6 +118,8 @@ int nxagentErrorHandler(Display *dpy, XErrorEvent *event)

Copy link
Member

Choose a reason for hiding this comment

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

"commt" typo in commit message.

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

free(nxagentKeyboard);
nxagentKeyboard = NULL;

if ((size = strlen(argv[i])) < 256)
Copy link
Member

Choose a reason for hiding this comment

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

Probably good to just drop this 255 character limitation here, I haven't found a reason why this would be necessary.

}

nxagentDialogName[NXAGENTDIALOGNAMELENGTH - 1] = '\0';
snprintf(nxagentDialogName, NXAGENTDIALOGNAMELENGTH, "NX - %.*s", length, nxagentSessionId);
Copy link
Member

Choose a reason for hiding this comment

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

I think that should be length - 1 (or 1 subtracted above) because it looks like we don't want to copy the leading - char either. At least the original code seems to have skipped it.

Copy link
Member

Choose a reason for hiding this comment

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

Ping on that?

Copy link
Member Author

@uli42 uli42 Jan 6, 2018

Choose a reason for hiding this comment

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

hmm, but we are subtracting 2+MD5+1 from the length already!?

Copy link
Member

Choose a reason for hiding this comment

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

2*MD5 + 1 actually... and yes, that's fine. I got confused by the different behaviors regarding the total string length (since snprintf expects the full length, but the str* family normally the length excluding a terminating NULL character). That's not relevant here, so the code is fine. My bad.

@@ -1838,43 +1834,56 @@ static FILE *nxagentLookForIconFile(char *iconName, const char *permission,
return NULL;
}

for(breakLoop = 0; breakLoop == 0 && fptr == NULL; )
for (int breakLoop = False; breakLoop == False && fptr == NULL; )
Copy link
Member

Choose a reason for hiding this comment

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

Can drop breakLoop by using:

  for (char *end = path; end == NULL && fptr == NULL; )

Copy link
Member Author

Choose a reason for hiding this comment

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

No, I'd have to check for end != NULL && fprt == NULL. Done.

Copy link
Member

Choose a reason for hiding this comment

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

Yes, sorry.

if ((keyboard_file = fopen(keyboard_file_path, "w"))) {
if (drules)
if (drules != NULL)
Copy link
Member

Choose a reason for hiding this comment

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

Changing this makes it weirdly inconsistent with the later code?

Copy link
Member

Choose a reason for hiding this comment

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

Ping on that?

Copy link
Member Author

Choose a reason for hiding this comment

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

ok, fixed

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed

@uli42 uli42 force-pushed the pr/fix_strings branch 2 times, most recently from d1da4bd to a711df7 Compare January 3, 2018 21:38
@uli42
Copy link
Member Author

uli42 commented Jan 3, 2018

ok, I fixed the four things you mentioned

Also comment the code and convert error messages to warnings.
and insert one single space
This is a partial copy from XlibInt.c's _XPrintDefaultError, which had
some minor changes since being copied. Update to reflect these
changes. Also comment some more lines as their result was unused an
cluttered the output.
I am not sure about the maximum font name length in X but just in
case use snprintf instead of memcpy to be sure nothing dangerous can
happen here.
even if we issue a FatalError afterwards
@Ionic Ionic merged commit 23c36c2 into ArcticaProject:3.6.x Jan 7, 2018
Ionic added a commit that referenced this pull request Jan 7, 2018
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.

None yet

3 participants