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

udev: readd format length parameter #6651

Closed
wants to merge 1 commit into from
Closed

udev: readd format length parameter #6651

wants to merge 1 commit into from

Conversation

tblume
Copy link
Contributor

@tblume tblume commented Aug 21, 2017

legacy udev had an udev rule parameter "format length" that could determine the
lenght of a string taken from sysfs attributes.
This seems to have become lost during the transition to systemd-udev.

Adding it back helps for backward compatibility and more userfriendly symlink names.

Copy link
Member

@evverx evverx left a comment

Choose a reason for hiding this comment

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

I think it would also be great to update udev-test.pl.

num = (int) strtoul(from, &tail, 10);
if (num > 0) {
log_debug("format length='%i'", num);
from = strjoina("%", tail);
Copy link
Member

Choose a reason for hiding this comment

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

Is it safe to call strjoina inside this loop?

Copy link
Member

Choose a reason for hiding this comment

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

stack allocation is never permissible in loops. strjoina() does stack allocation, hence no, it's not safe.

if (num > 0) {
log_debug("format length='%i'", num);
from = strjoina("%", tail);
l = num+1;
Copy link
Member

Choose a reason for hiding this comment

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

What happens to dest if num+1 is greater than size?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

num+1 > size should be handeled by the backend function.
The function strpcpy (src/basic/strxcpyx.c) that is called from subst_format_var will only copy up to the length of the source string:

size_t strpcpy(char **dest, size_t size, const char *src) {
[...]
len = strlen(src);
if (len >= size) {
if (size > 1)
*dest = mempcpy(*dest, src, size-1);
size = 0;
} else {
if (len > 0) {
*dest = mempcpy(*dest, src, len);
size -= len;
}
}

Copy link
Member

Choose a reason for hiding this comment

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

It seems that the length of src might be greater than the length of dst in this case.

Copy link
Member

Choose a reason for hiding this comment

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

In other words, l shows how many bytes can be written to dst. If l is increased and strlen(src) is greater than the previous value of l, then dst might be overflowed.

legacy udev had an udev rule parameter "format length" that could determine the
lenght of a string taken from sysfs attributes.
This seems to have become lost during the transition to systemd-udev.

Adding it back helps for backward compatibility and more userfriendly symlink names.
@evverx
Copy link
Member

evverx commented Aug 21, 2017

I've changed test-udev.pl a bit:

@@ -289,7 +289,7 @@ EOF
                 not_exp_name    => "not" ,
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", SYMLINK+="not"
-SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", SYMLINK+="%c-%n"
+SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", SYMLINK+="%14c-%n"
 EOF

. I got the following:

==10735== Invalid write of size 1
==10735==    at 0x4C34F44: __GI_mempcpy (vg_replace_strmem.c:1518)
==10735==    by 0x4F18AA9: strpcpy (strxcpyx.c:53)
==10735==    by 0x117E08: subst_format_var (udev-event.c:182)
==10735==    by 0x118BA2: udev_event_apply_format (udev-event.c:418)
==10735==    by 0x125652: udev_rules_apply_to_event (udev-rules.c:2330)
==10735==    by 0x11AA7E: udev_event_execute_rules (udev-event.c:903)
==10735==    by 0x1176CC: main (test-udev.c:137)
==10735==  Address 0xf is not stack'd, malloc'd or (recently) free'd
==10735==
==10735==
==10735== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==10735==  Access not within mapped region at address 0xF
==10735==    at 0x4C34F44: __GI_mempcpy (vg_replace_strmem.c:1518)
==10735==    by 0x4F18AA9: strpcpy (strxcpyx.c:53)
==10735==    by 0x117E08: subst_format_var (udev-event.c:182)
==10735==    by 0x118BA2: udev_event_apply_format (udev-event.c:418)
==10735==    by 0x125652: udev_rules_apply_to_event (udev-rules.c:2330)
==10735==    by 0x11AA7E: udev_event_execute_rules (udev-event.c:903)
==10735==    by 0x1176CC: main (test-udev.c:137)

.

By the way, judging by a0ee5a0, it seems that %number was removed on purpose. Does anybody know why?

@tblume
Copy link
Contributor Author

tblume commented Aug 23, 2017

Thanks for the investigation, I wasn't aware that the format length feature has been explicitely removed. Waiting for feedback about the reason before continuing.

Concerning the dst overflow, shouldn't this rather be fixed in the strpcpy function, instead of taking care of this via the calling function?
IMHO, if strpcpy uses strlen(src) instead of l, it should also take care that the size of dst gets reset to strlen(src), no?

@evverx
Copy link
Member

evverx commented Aug 24, 2017

I'm not sure what strpcpy can do when it receives the wrong length of the destination string:

s1 = new(char, 5)
strpcpy(&s1, 7, "012345678")

Only the caller knows that 5 should be passed instead of 7.

@tblume
Copy link
Contributor Author

tblume commented Aug 24, 2017

I see, thanks for elaboration.

@evverx
Copy link
Member

evverx commented Aug 24, 2017

You're welcome. Actually, this PR has helped me to find #6664 and I'm a bit worried that bugs of that kind seem to be quite common in udev.

@tblume
Copy link
Contributor Author

tblume commented Aug 25, 2017

@kaysievers can you give some background about the reason for a0ee5a0 ?

@kaysievers
Copy link
Contributor

I don't remember any specific reasons about this one, just that we removed a whole bunch of magic string mangling; we did not want udev provide shell-like features. People asked for more of them, and we thought they should use a shell, if they need to do more complicated things.

@poettering
Copy link
Member

I think we should have less string mangling support in udev rules, not more. hence, let's not add this, I see little point in restoring something that was removed 8 years ago and nobody noticed or missed so far.

Closing. I hope this makes sense.

@poettering poettering closed this Aug 30, 2017
@tblume tblume deleted the udev-readd-format-lenght branch December 7, 2017 11:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging this pull request may close these issues.

None yet

4 participants