diff mbox series

toastergui/views: Replace os.system call with improved parameter handling

Message ID 20260928111208.3011807-1-richard.purdie@linuxfoundation.org
State New
Headers show
Series toastergui/views: Replace os.system call with improved parameter handling | expand

Commit Message

Richard Purdie Sept. 28, 2026, 11:12 a.m. UTC
Using bash to handle execution parameters isn't a great idea, particularly using
os.system. In theory this could be exploited by injecting shell code through the
placeholders although whether this can be done without security tokens is unclear.

Regardless, we have been cleaning up shell=True and similar calls in the codebase.
Instead use shlex to parse the callback command, then we can iterate the parameters
to perform any expansions needed and avoid the need to call any shell expansion.
Any invalid data will then just become an invalid image target to bitbake.

Reported-by: Lei Zhang <18792670849@163.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 lib/toaster/toastergui/views.py | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/lib/toaster/toastergui/views.py b/lib/toaster/toastergui/views.py
index 061e6436c85..3192b7270d6 100644
--- a/lib/toaster/toastergui/views.py
+++ b/lib/toaster/toastergui/views.py
@@ -8,6 +8,7 @@ 
 
 import ast
 import re
+import shlex
 import subprocess
 import sys
 
@@ -1556,7 +1557,7 @@  if True:
     # perform the final actions for the project specific page
     def project_specific_finalize(cmnd, pid):
         project = Project.objects.get(pk=pid)
-        callback = project.get_variable(Project.PROJECT_SPECIFIC_CALLBACK)
+        callback = shlex.split(project.get_variable(Project.PROJECT_SPECIFIC_CALLBACK) or "")
         if "update" == cmnd:
             # Delete all '_PROJECT_PREPARE_' builds
             for b in Build.objects.all().filter(project=project):
@@ -1569,16 +1570,15 @@  if True:
                     management.call_command('builddelete', str(b.id), interactive=False)
             # perform callback at this last moment if defined, in case Toaster gets shutdown next
             default_target = project.get_variable(Project.PROJECT_SPECIFIC_DEFAULTIMAGE)
-            if callback:
-                callback = callback.replace("<IMAGE>",default_target)
+            for i in range(len(callback)):
+                callback[i] = callback[i].replace("<IMAGE>", default_target)
         if "cancel" == cmnd:
-            if callback:
-                callback = callback.replace("<IMAGE>","none")
-                callback = callback.replace("--update","--cancel")
+            for i in range(len(callback)):
+                callback[i] = callback[i].replace("<IMAGE>", "none")
+                callback[i] = callback[i].replace("--update", "--cancel")
         # perform callback at this last moment if defined, in case this Toaster gets shutdown next
-        ret = ''
         if callback:
-            ret = os.system('bash -c "%s"' % callback)
+            subprocess.run(callback, shell=False)
             project.set_variable(Project.PROJECT_SPECIFIC_CALLBACK,'')
         # Delete the temp project specific variables
         project.set_variable(Project.PROJECT_SPECIFIC_ISNEW,'')