]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev: do not import property value from truncated line of program result
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 15 Dec 2021 22:47:24 +0000 (07:47 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 25 Dec 2021 06:13:19 +0000 (15:13 +0900)
src/udev/test-udev-event.c
src/udev/udev-event.c
src/udev/udev-event.h
src/udev/udev-rules.c

index b1a631dea2f17f37b4a589328771ddc5816cc140..2e89fa8f0d41e0d06b1156eef6667da3ee34794c 100644 (file)
@@ -17,7 +17,7 @@ static void test_event_spawn_core(bool with_pidfd, const char *cmd, char result_
 
         assert_se(sd_device_new_from_syspath(&dev, "/sys/class/net/lo") >= 0);
         assert_se(event = udev_event_new(dev, 0, NULL, LOG_DEBUG));
-        assert_se(udev_event_spawn(event, 5 * USEC_PER_SEC, SIGKILL, false, cmd, result_buf, BUF_SIZE) == 0);
+        assert_se(udev_event_spawn(event, 5 * USEC_PER_SEC, SIGKILL, false, cmd, result_buf, BUF_SIZE, NULL) == 0);
 
         assert_se(unsetenv("SYSTEMD_PIDFD") >= 0);
 }
index eb576508dead8f34d92b3cb04c7944bdc55054b3..aa7d229816bca1683faa0503e3c6ab1cc0b91769 100644 (file)
@@ -50,6 +50,7 @@ typedef struct Spawn {
         char *result;
         size_t result_size;
         size_t result_len;
+        bool truncated;
 } Spawn;
 
 UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl, int log_level) {
@@ -569,7 +570,6 @@ int udev_check_format(const char *value, size_t *offset, const char **hint) {
 static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
         Spawn *spawn = userdata;
         char buf[4096], *p;
-        bool full = false;
         size_t size;
         ssize_t l;
         int r;
@@ -601,7 +601,7 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd
                 log_device_warning(spawn->device, "Truncating stdout of '%s' up to %zu byte.",
                                    spawn->cmd, spawn->result_size);
                 l--;
-                full = true;
+                spawn->truncated = true;
         }
 
         p[l] = '\0';
@@ -624,7 +624,7 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd
                                          fd == spawn->fd_stdout ? "out" : "err", *q);
         }
 
-        if (l == 0 || full)
+        if (l == 0 || spawn->truncated)
                 return 0;
 
 reenable:
@@ -763,12 +763,16 @@ static int spawn_wait(Spawn *spawn) {
         return sd_event_loop(e);
 }
 
-int udev_event_spawn(UdevEvent *event,
-                     usec_t timeout_usec,
-                     int timeout_signal,
-                     bool accept_failure,
-                     const char *cmd,
-                     char *result, size_t ressize) {
+int udev_event_spawn(
+                UdevEvent *event,
+                usec_t timeout_usec,
+                int timeout_signal,
+                bool accept_failure,
+                const char *cmd,
+                char *result,
+                size_t ressize,
+                bool *ret_truncated) {
+
         _cleanup_close_pair_ int outpipe[2] = {-1, -1}, errpipe[2] = {-1, -1};
         _cleanup_strv_free_ char **argv = NULL;
         char **envp = NULL;
@@ -859,6 +863,9 @@ int udev_event_spawn(UdevEvent *event,
         if (result)
                 result[spawn.result_len] = '\0';
 
+        if (ret_truncated)
+                *ret_truncated = spawn.truncated;
+
         return r; /* 0 for success, and positive if the program failed */
 }
 
@@ -1133,7 +1140,7 @@ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_s
 
                         log_device_debug(event->dev, "Running command \"%s\"", command);
 
-                        r = udev_event_spawn(event, timeout_usec, timeout_signal, false, command, NULL, 0);
+                        r = udev_event_spawn(event, timeout_usec, timeout_signal, false, command, NULL, 0, NULL);
                         if (r < 0)
                                 log_device_warning_errno(event->dev, r, "Failed to execute '%s', ignoring: %m", command);
                         else if (r > 0) /* returned value is positive when program fails */
index 823055ddb237512b776dfa837cd59cb741738c6c..d201fb580a5c5458c43d6912f23a3b4104e865d3 100644 (file)
@@ -66,7 +66,8 @@ int udev_event_spawn(
                 bool accept_failure,
                 const char *cmd,
                 char *result,
-                size_t ressize);
+                size_t ressize,
+                bool *ret_truncated);
 int udev_event_execute_rules(
                 UdevEvent *event,
                 int inotify_fd,
index b353b5b8106c4181c0fd96f5085fb8d0e4fcb099..a610dea0d975a655a35e9e425b926ee825637f24 100644 (file)
@@ -1740,7 +1740,7 @@ static int udev_rule_apply_token_to_event(
 
                 log_rule_debug(dev, rules, "Running PROGRAM '%s'", buf);
 
-                r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof(result));
+                r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof(result), NULL);
                 if (r != 0) {
                         if (r < 0)
                                 log_rule_warning_errno(dev, rules, r, "Failed to execute \"%s\": %m", buf);
@@ -1826,7 +1826,7 @@ static int udev_rule_apply_token_to_event(
 
                 log_rule_debug(dev, rules, "Importing properties from results of '%s'", buf);
 
-                r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof result);
+                r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof result, &truncated);
                 if (r != 0) {
                         if (r < 0)
                                 log_rule_warning_errno(dev, rules, r, "Failed to execute '%s', ignoring: %m", buf);
@@ -1835,6 +1835,18 @@ static int udev_rule_apply_token_to_event(
                         return token->op == OP_NOMATCH;
                 }
 
+                if (truncated) {
+                        bool found = false;
+
+                        /* Drop the last line. */
+                        for (char *p = buf + strlen(buf) - 1; p >= buf; p--)
+                                if (strchr(NEWLINE, *p)) {
+                                        *p = '\0';
+                                        found = true;
+                                } else if (found)
+                                        break;
+                }
+
                 r = strv_split_newlines_full(&lines, result, EXTRACT_RETAIN_ESCAPE);
                 if (r < 0)
                         log_rule_warning_errno(dev, rules, r,