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

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>
(Bitbake rev: d3b32587c2314febf96897f97e0172790b4fc1cf)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Signed-off-by: Paul Barker <paul@pbarker.dev>
This commit is contained in:
Richard Purdie authored and Paul Barker committed 2026-10-07 16:08:04 +01:00
1 parent 3a3d07f625
commit 3df97be56e
1 file changed
+8 -8
+8 -8
View File
@@ -8,6 +8,7 @@
import ast
import re
import shlex
import subprocess
import sys
@@ -1558,7 +1559,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):
@@ -1571,16 +1572,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,'')