mirror of
https://github.com/QubesOS/qubes-doc.git
synced 2024-10-01 01:25:40 -04:00
Fix over indented code blocks
This commit is contained in:
parent
0824b2d196
commit
752f1d4ddc
@ -113,7 +113,7 @@ And this should produce a shiny new ISO.
|
||||
You can also build selected component separately. Eg. to compile only gui virtualization agent/daemon:
|
||||
|
||||
```shell
|
||||
make gui-daemon
|
||||
make gui-daemon
|
||||
```
|
||||
|
||||
You can get a full list from make help.
|
||||
|
@ -157,14 +157,14 @@ Security coding guidelines
|
||||
- Use `untrusted_` prefix for all variables that hold values read from untrusted party and which have not yet been verified to be decent, e.g.:
|
||||
|
||||
~~~
|
||||
read_struct(untrusted_conf);
|
||||
/* sanitize start */
|
||||
if (untrusted_conf.width > MAX_WINDOW_WIDTH)
|
||||
untrusted_conf.width = MAX_WINDOW_WIDTH;
|
||||
if (untrusted_conf.height > MAX_WINDOW_HEIGHT)
|
||||
untrusted_conf.height = MAX_WINDOW_HEIGHT;
|
||||
width = untrusted_conf.width;
|
||||
height = untrusted_conf.height;
|
||||
read_struct(untrusted_conf);
|
||||
/* sanitize start */
|
||||
if (untrusted_conf.width > MAX_WINDOW_WIDTH)
|
||||
untrusted_conf.width = MAX_WINDOW_WIDTH;
|
||||
if (untrusted_conf.height > MAX_WINDOW_HEIGHT)
|
||||
untrusted_conf.height = MAX_WINDOW_HEIGHT;
|
||||
width = untrusted_conf.width;
|
||||
height = untrusted_conf.height;
|
||||
~~~
|
||||
|
||||
- Use others variables, without the `untrusted_` prefix to hold the sanitized values, as shown above.
|
||||
|
@ -47,70 +47,70 @@ Our test runner runs mostly the same as the standard one, but it has some nice a
|
||||
You can use `python3 -m qubes.tests.run -h` to get usage information:
|
||||
|
||||
```
|
||||
[user@dom0 ~]$ python3 -m qubes.tests.run -h
|
||||
usage: run.py [-h] [--verbose] [--quiet] [--list] [--failfast] [--no-failfast]
|
||||
[--do-not-clean] [--do-clean] [--loglevel LEVEL]
|
||||
[--logfile FILE] [--syslog] [--no-syslog] [--kmsg] [--no-kmsg]
|
||||
[TESTNAME [TESTNAME ...]]
|
||||
[user@dom0 ~]$ python3 -m qubes.tests.run -h
|
||||
usage: run.py [-h] [--verbose] [--quiet] [--list] [--failfast] [--no-failfast]
|
||||
[--do-not-clean] [--do-clean] [--loglevel LEVEL]
|
||||
[--logfile FILE] [--syslog] [--no-syslog] [--kmsg] [--no-kmsg]
|
||||
[TESTNAME [TESTNAME ...]]
|
||||
|
||||
positional arguments:
|
||||
TESTNAME list of tests to run named like in description
|
||||
(default: run all tests)
|
||||
positional arguments:
|
||||
TESTNAME list of tests to run named like in description
|
||||
(default: run all tests)
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--verbose, -v increase console verbosity level
|
||||
--quiet, -q decrease console verbosity level
|
||||
--list, -l list all available tests and exit
|
||||
--failfast, -f stop on the first fail, error or unexpected success
|
||||
--no-failfast disable --failfast
|
||||
--loglevel LEVEL, -L LEVEL
|
||||
logging level for file and syslog forwarding (one of:
|
||||
NOTSET, DEBUG, INFO, WARN, WARNING, ERROR, CRITICAL;
|
||||
default: DEBUG)
|
||||
--logfile FILE, -o FILE
|
||||
if set, test run will be also logged to file
|
||||
--syslog reenable logging to syslog
|
||||
--no-syslog disable logging to syslog
|
||||
--kmsg, --very-brave-or-very-stupid
|
||||
log most important things to kernel ring-buffer
|
||||
--no-kmsg, --i-am-smarter-than-kay-sievers
|
||||
do not abuse kernel ring-buffer
|
||||
--allow-running-along-qubesd
|
||||
allow running in parallel with qubesd; this is
|
||||
DANGEROUS and WILL RESULT IN INCONSISTENT SYSTEM STATE
|
||||
--break-to-repl break to REPL after tests
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--verbose, -v increase console verbosity level
|
||||
--quiet, -q decrease console verbosity level
|
||||
--list, -l list all available tests and exit
|
||||
--failfast, -f stop on the first fail, error or unexpected success
|
||||
--no-failfast disable --failfast
|
||||
--loglevel LEVEL, -L LEVEL
|
||||
logging level for file and syslog forwarding (one of:
|
||||
NOTSET, DEBUG, INFO, WARN, WARNING, ERROR, CRITICAL;
|
||||
default: DEBUG)
|
||||
--logfile FILE, -o FILE
|
||||
if set, test run will be also logged to file
|
||||
--syslog reenable logging to syslog
|
||||
--no-syslog disable logging to syslog
|
||||
--kmsg, --very-brave-or-very-stupid
|
||||
log most important things to kernel ring-buffer
|
||||
--no-kmsg, --i-am-smarter-than-kay-sievers
|
||||
do not abuse kernel ring-buffer
|
||||
--allow-running-along-qubesd
|
||||
allow running in parallel with qubesd; this is
|
||||
DANGEROUS and WILL RESULT IN INCONSISTENT SYSTEM STATE
|
||||
--break-to-repl break to REPL after tests
|
||||
|
||||
When running only specific tests, write their names like in log, in format:
|
||||
MODULE+"/"+CLASS+"/"+FUNCTION. MODULE should omit initial "qubes.tests.".
|
||||
Example: basic/TC_00_Basic/test_000_create
|
||||
When running only specific tests, write their names like in log, in format:
|
||||
MODULE+"/"+CLASS+"/"+FUNCTION. MODULE should omit initial "qubes.tests.".
|
||||
Example: basic/TC_00_Basic/test_000_create
|
||||
```
|
||||
|
||||
For instance, to run only the tests for the fedora-21 template, you can use the `-l` option, then filter the list:
|
||||
|
||||
```
|
||||
[user@dom0 ~]$ python3 -m qubes.tests.run -l | grep fedora-21
|
||||
network/VmNetworking_fedora-21/test_000_simple_networking
|
||||
network/VmNetworking_fedora-21/test_010_simple_proxyvm
|
||||
network/VmNetworking_fedora-21/test_020_simple_proxyvm_nm
|
||||
network/VmNetworking_fedora-21/test_030_firewallvm_firewall
|
||||
network/VmNetworking_fedora-21/test_040_inter_vm
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_000_start_shutdown
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_010_run_gui_app
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_050_qrexec_simple_eof
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_051_qrexec_simple_eof_reverse
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_052_qrexec_vm_service_eof
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_053_qrexec_vm_service_eof_reverse
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_060_qrexec_exit_code_dom0
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_065_qrexec_exit_code_vm
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_100_qrexec_filecopy
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_110_qrexec_filecopy_deny
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_120_qrexec_filecopy_self
|
||||
vm_qrexec_gui/TC_20_DispVM_fedora-21/test_000_prepare_dvm
|
||||
vm_qrexec_gui/TC_20_DispVM_fedora-21/test_010_simple_dvm_run
|
||||
vm_qrexec_gui/TC_20_DispVM_fedora-21/test_020_gui_app
|
||||
vm_qrexec_gui/TC_20_DispVM_fedora-21/test_030_edit_file
|
||||
[user@dom0 ~]$ sudo -E python3 -m qubes.tests.run -v `python3 -m qubes.tests.run -l | grep fedora-21`
|
||||
[user@dom0 ~]$ python3 -m qubes.tests.run -l | grep fedora-21
|
||||
network/VmNetworking_fedora-21/test_000_simple_networking
|
||||
network/VmNetworking_fedora-21/test_010_simple_proxyvm
|
||||
network/VmNetworking_fedora-21/test_020_simple_proxyvm_nm
|
||||
network/VmNetworking_fedora-21/test_030_firewallvm_firewall
|
||||
network/VmNetworking_fedora-21/test_040_inter_vm
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_000_start_shutdown
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_010_run_gui_app
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_050_qrexec_simple_eof
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_051_qrexec_simple_eof_reverse
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_052_qrexec_vm_service_eof
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_053_qrexec_vm_service_eof_reverse
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_060_qrexec_exit_code_dom0
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_065_qrexec_exit_code_vm
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_100_qrexec_filecopy
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_110_qrexec_filecopy_deny
|
||||
vm_qrexec_gui/TC_00_AppVM_fedora-21/test_120_qrexec_filecopy_self
|
||||
vm_qrexec_gui/TC_20_DispVM_fedora-21/test_000_prepare_dvm
|
||||
vm_qrexec_gui/TC_20_DispVM_fedora-21/test_010_simple_dvm_run
|
||||
vm_qrexec_gui/TC_20_DispVM_fedora-21/test_020_gui_app
|
||||
vm_qrexec_gui/TC_20_DispVM_fedora-21/test_030_edit_file
|
||||
[user@dom0 ~]$ sudo -E python3 -m qubes.tests.run -v `python3 -m qubes.tests.run -l | grep fedora-21`
|
||||
```
|
||||
|
||||
Example test run:
|
||||
@ -120,7 +120,7 @@ Example test run:
|
||||
Tests are also compatible with nose2 test runner, so you can use this instead:
|
||||
|
||||
```bash
|
||||
sudo systemctl stop qubesd; sudo -E nose2 -v --plugin nose2.plugins.loader.loadtests qubes.tests; sudo systemctl start qubesd
|
||||
sudo systemctl stop qubesd; sudo -E nose2 -v --plugin nose2.plugins.loader.loadtests qubes.tests; sudo systemctl start qubesd
|
||||
```
|
||||
|
||||
This may be especially useful together with various nose2 plugins to store tests results (for example `nose2.plugins.junitxml`), to ease presenting results. This is what we use on [OpenQA].
|
||||
@ -179,16 +179,16 @@ You'll also need to add your test at the bottom of the `__init__.py` file, in th
|
||||
Again, given the hypothetical `example.py` test:
|
||||
|
||||
~~~python
|
||||
for modname in (
|
||||
'qubes.tests.basic',
|
||||
'qubes.tests.dom0_update',
|
||||
'qubes.tests.network',
|
||||
'qubes.tests.vm_qrexec_gui',
|
||||
'qubes.tests.backup',
|
||||
'qubes.tests.backupcompatibility',
|
||||
'qubes.tests.regressions',
|
||||
'qubes.tests.example', # This is our newly added test
|
||||
):
|
||||
for modname in (
|
||||
'qubes.tests.basic',
|
||||
'qubes.tests.dom0_update',
|
||||
'qubes.tests.network',
|
||||
'qubes.tests.vm_qrexec_gui',
|
||||
'qubes.tests.backup',
|
||||
'qubes.tests.backupcompatibility',
|
||||
'qubes.tests.regressions',
|
||||
'qubes.tests.example', # This is our newly added test
|
||||
):
|
||||
~~~
|
||||
|
||||
### Testing PyQt applications
|
||||
|
@ -43,19 +43,19 @@ You have to select the area in which you suspect less than optimal performance.
|
||||
Replace
|
||||
|
||||
```python
|
||||
def foo(self, bar):
|
||||
# function content
|
||||
def foo(self, bar):
|
||||
# function content
|
||||
```
|
||||
|
||||
with
|
||||
|
||||
```python
|
||||
def foo(self, *args, **kwargs):
|
||||
profile.runctx('self.real_foo(*args, **kwargs)', globals(), locals(),
|
||||
time.strftime('/home/user/profiling/foo-%Y%m%d-%H%M%S.pstats'))
|
||||
def foo(self, *args, **kwargs):
|
||||
profile.runctx('self.real_foo(*args, **kwargs)', globals(), locals(),
|
||||
time.strftime('/home/user/profiling/foo-%Y%m%d-%H%M%S.pstats'))
|
||||
|
||||
def real_foo(self, bar):
|
||||
# function content
|
||||
def real_foo(self, bar):
|
||||
# function content
|
||||
```
|
||||
|
||||
### Run application
|
||||
|
@ -23,37 +23,37 @@ First, do a clean install from ISO you built or grabbed elsewhere.
|
||||
You have to fix network, because it is intentionally broken. This script should reenable your network card without depending on anything else.
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
#!/bin/sh
|
||||
|
||||
# adjust this for your NIC (run lspci)
|
||||
BDF=0000:02:00.0
|
||||
# adjust this for your NIC (run lspci)
|
||||
BDF=0000:02:00.0
|
||||
|
||||
prog=$(basename $0)
|
||||
prog=$(basename $0)
|
||||
|
||||
pciunbind() {
|
||||
local path
|
||||
path=/sys/bus/pci/devices/${1}/driver/unbind
|
||||
if ! [ -w ${path} ]; then
|
||||
echo "${prog}: Device ${1} not bound"
|
||||
return 1
|
||||
fi
|
||||
echo -n ${1} >${path}
|
||||
}
|
||||
pciunbind() {
|
||||
local path
|
||||
path=/sys/bus/pci/devices/${1}/driver/unbind
|
||||
if ! [ -w ${path} ]; then
|
||||
echo "${prog}: Device ${1} not bound"
|
||||
return 1
|
||||
fi
|
||||
echo -n ${1} >${path}
|
||||
}
|
||||
|
||||
pcibind() {
|
||||
local path
|
||||
path=/sys/bus/pci/drivers/${2}/bind
|
||||
if ! [ -w ${path} ]; then
|
||||
echo "${prog}: Driver ${2} not found"
|
||||
return 1
|
||||
fi
|
||||
echo ${1} >${path}
|
||||
}
|
||||
pcibind() {
|
||||
local path
|
||||
path=/sys/bus/pci/drivers/${2}/bind
|
||||
if ! [ -w ${path} ]; then
|
||||
echo "${prog}: Driver ${2} not found"
|
||||
return 1
|
||||
fi
|
||||
echo ${1} >${path}
|
||||
}
|
||||
|
||||
pciunbind ${BDF}
|
||||
pcibind ${BDF} e1000e
|
||||
pciunbind ${BDF}
|
||||
pcibind ${BDF} e1000e
|
||||
|
||||
dhclient
|
||||
dhclient
|
||||
```
|
||||
|
||||
TODO: describe how to run this at every startup
|
||||
@ -97,51 +97,51 @@ This step is optional, but very helpful. Put these scripts somewhere in your `${
|
||||
`qtb-runtests`:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
#!/bin/sh
|
||||
|
||||
ssh testbench python -m qubes.tests.run
|
||||
ssh testbench python -m qubes.tests.run
|
||||
```
|
||||
|
||||
`qtb-install`:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
#!/bin/sh
|
||||
|
||||
TMPDIR=/tmp/qtb-rpms
|
||||
TMPDIR=/tmp/qtb-rpms
|
||||
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "usage: $(basename $0) <rpmfile> ..."
|
||||
exit 2
|
||||
fi
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "usage: $(basename $0) <rpmfile> ..."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
set -e
|
||||
set -e
|
||||
|
||||
ssh testbench mkdir -p "${TMPDIR}"
|
||||
scp "${@}" testbench:"${TMPDIR}"
|
||||
ssh testbench mkdir -p "${TMPDIR}"
|
||||
scp "${@}" testbench:"${TMPDIR}"
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
ssh testbench sudo rpm -i --replacepkgs --replacefiles "${TMPDIR}/$(basename ${1})"
|
||||
shift
|
||||
done
|
||||
while [ $# -gt 0 ]; do
|
||||
ssh testbench sudo rpm -i --replacepkgs --replacefiles "${TMPDIR}/$(basename ${1})"
|
||||
shift
|
||||
done
|
||||
```
|
||||
|
||||
`qtb-iterate`:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -e
|
||||
|
||||
# substitute path to your builder installation
|
||||
pushd ${HOME}/builder >/dev/null
|
||||
# substitute path to your builder installation
|
||||
pushd ${HOME}/builder >/dev/null
|
||||
|
||||
# the following are needed only if you have sources outside builder
|
||||
#rm -rf qubes-src/core-admin
|
||||
#make COMPONENTS=core-admin get-sources
|
||||
# the following are needed only if you have sources outside builder
|
||||
#rm -rf qubes-src/core-admin
|
||||
#make COMPONENTS=core-admin get-sources
|
||||
|
||||
make core-admin
|
||||
qtb-install qubes-src/core-admin/rpm/x86_64/qubes-core-dom0-*.rpm
|
||||
qtb-runtests
|
||||
make core-admin
|
||||
qtb-install qubes-src/core-admin/rpm/x86_64/qubes-core-dom0-*.rpm
|
||||
qtb-runtests
|
||||
```
|
||||
|
||||
### Hooking git
|
||||
@ -151,17 +151,17 @@ I (woju) have those two git hooks. They ensure tests are passing (or are marked
|
||||
`core-admin/.git/hooks/pre-commit`: (you may retain also the default hook, here omitted for readability)
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -e
|
||||
|
||||
python -c "import sys, qubes.tests.run; sys.exit(not qubes.tests.run.main())"
|
||||
python -c "import sys, qubes.tests.run; sys.exit(not qubes.tests.run.main())"
|
||||
```
|
||||
|
||||
`core-admin/.git/hooks/pre-push`:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
#!/bin/sh
|
||||
|
||||
exec qtb-iterate
|
||||
exec qtb-iterate
|
||||
```
|
||||
|
@ -25,11 +25,11 @@ Things get complicated if you need to perform kernel debugging or troubleshoot p
|
||||
- To determine which dom0 pty corresponds to VM's serial port you need to read xenstore, example script below:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
#!/bin/sh
|
||||
|
||||
id1=$(xl domid "$1-dm")
|
||||
tty1=$(xenstore-read /local/domain/${id1}/device/console/3/tty)
|
||||
echo $tty1
|
||||
id1=$(xl domid "$1-dm")
|
||||
tty1=$(xenstore-read /local/domain/${id1}/device/console/3/tty)
|
||||
echo $tty1
|
||||
```
|
||||
|
||||
Pass it a running VM name and it will output the corresponding pty name.
|
||||
@ -37,13 +37,13 @@ Pass it a running VM name and it will output the corresponding pty name.
|
||||
- To connect both ptys you can use [socat](http://www.dest-unreach.org/socat/) like that:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
#!/bin/sh
|
||||
|
||||
id1=$(xl domid "$1-dm")
|
||||
id2=$(xl domid "$2-dm")
|
||||
tty1=$(xenstore-read /local/domain/${id1}/device/console/3/tty)
|
||||
tty2=$(xenstore-read /local/domain/${id2}/device/console/3/tty)
|
||||
socat $tty1,raw $tty2,raw
|
||||
id1=$(xl domid "$1-dm")
|
||||
id2=$(xl domid "$2-dm")
|
||||
tty1=$(xenstore-read /local/domain/${id1}/device/console/3/tty)
|
||||
tty2=$(xenstore-read /local/domain/${id2}/device/console/3/tty)
|
||||
socat $tty1,raw $tty2,raw
|
||||
```
|
||||
|
||||
...but there is a catch. Xen seems to process the traffic that goes through serial ports and changes all **0x0a** bytes into **0x0d, 0x0a** pairs (newline conversion). I didn't find a way to turn that off (setting ptys to raw mode didn't change anything) and it's not mentioned anywhere on the Internet, so maybe it's something on my system. If the above script works for you then you don't need anything more in dom0.
|
||||
@ -79,115 +79,115 @@ Pass it a running VM name and it will output the corresponding pty name.
|
||||
...then you're most likely a victim of the CRLF issue mentioned above. To get around it I wrote a small utility that basically does what socat would do and additionally corrects those replaced bytes in the stream. It's not pretty but it works:
|
||||
|
||||
```c
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <termios.h>
|
||||
|
||||
int fd1, fd2;
|
||||
char mark = ' ';
|
||||
int fd1, fd2;
|
||||
char mark = ' ';
|
||||
|
||||
void out(unsigned char c)
|
||||
void out(unsigned char c)
|
||||
{
|
||||
static int count = 0;
|
||||
static unsigned char buf[17] = {0};
|
||||
|
||||
// relay to ouptput port
|
||||
write(fd2, &c, 1);
|
||||
fprintf(stderr, "%c", mark);
|
||||
|
||||
/* dump all data going over the line
|
||||
if (count == 0)
|
||||
fprintf(stderr, "%c", mark);
|
||||
fprintf(stderr, "%02x ", c);
|
||||
if (c >= 0x20 && c < 0x80)
|
||||
buf[count] = c;
|
||||
else
|
||||
buf[count] = '.';
|
||||
count++;
|
||||
if (count == 0x10)
|
||||
{
|
||||
count = 0;
|
||||
fprintf(stderr, " %s\n", buf);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
unsigned char c = 0;
|
||||
struct termios tio;
|
||||
ssize_t size;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s pty1 pty2 [mark character]\n", argv[0]);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
fd1 = open(argv[1], O_RDONLY | O_NOCTTY);
|
||||
if (fd1 <= 0)
|
||||
{
|
||||
perror("open fd1");
|
||||
return errno;
|
||||
}
|
||||
fd2 = open(argv[2], O_WRONLY | O_NOCTTY);
|
||||
if (fd2 <= 0)
|
||||
{
|
||||
perror("open fd2");
|
||||
return errno;
|
||||
}
|
||||
/*
|
||||
// This doesn't make any difference which supports the theory
|
||||
// that it's Xen who corrupts the byte stream.
|
||||
cfmakeraw(&tio);
|
||||
if (tcsetattr(fd1, TCSANOW, &tio) < 0)
|
||||
{
|
||||
perror("tcsetattr 1");
|
||||
return errno;
|
||||
}
|
||||
if (tcsetattr(fd2, TCSANOW, &tio) < 0)
|
||||
{
|
||||
perror("tcsetattr 2");
|
||||
return errno;
|
||||
}
|
||||
*/
|
||||
if (argc == 4)
|
||||
mark = argv[3][0];
|
||||
|
||||
while (1)
|
||||
{
|
||||
size = read(fd1, &c, 1);
|
||||
if (size <= 0)
|
||||
break;
|
||||
|
||||
parse:
|
||||
if (c == 0x0d)
|
||||
{
|
||||
static int count = 0;
|
||||
static unsigned char buf[17] = {0};
|
||||
|
||||
// relay to ouptput port
|
||||
write(fd2, &c, 1);
|
||||
fprintf(stderr, "%c", mark);
|
||||
|
||||
/* dump all data going over the line
|
||||
if (count == 0)
|
||||
fprintf(stderr, "%c", mark);
|
||||
fprintf(stderr, "%02x ", c);
|
||||
if (c >= 0x20 && c < 0x80)
|
||||
buf[count] = c;
|
||||
size = read(fd1, &c, 1);
|
||||
if (size <= 0)
|
||||
{
|
||||
out(0x0d);
|
||||
break;
|
||||
}
|
||||
if (c == 0x0a)
|
||||
{
|
||||
out(0x0a);
|
||||
}
|
||||
else
|
||||
buf[count] = '.';
|
||||
count++;
|
||||
if (count == 0x10)
|
||||
{
|
||||
count = 0;
|
||||
fprintf(stderr, " %s\n", buf);
|
||||
out(0x0d);
|
||||
goto parse;
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
out(c);
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
unsigned char c = 0;
|
||||
struct termios tio;
|
||||
ssize_t size;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s pty1 pty2 [mark character]\n", argv[0]);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
fd1 = open(argv[1], O_RDONLY | O_NOCTTY);
|
||||
if (fd1 <= 0)
|
||||
{
|
||||
perror("open fd1");
|
||||
return errno;
|
||||
}
|
||||
fd2 = open(argv[2], O_WRONLY | O_NOCTTY);
|
||||
if (fd2 <= 0)
|
||||
{
|
||||
perror("open fd2");
|
||||
return errno;
|
||||
}
|
||||
/*
|
||||
// This doesn't make any difference which supports the theory
|
||||
// that it's Xen who corrupts the byte stream.
|
||||
cfmakeraw(&tio);
|
||||
if (tcsetattr(fd1, TCSANOW, &tio) < 0)
|
||||
{
|
||||
perror("tcsetattr 1");
|
||||
return errno;
|
||||
}
|
||||
if (tcsetattr(fd2, TCSANOW, &tio) < 0)
|
||||
{
|
||||
perror("tcsetattr 2");
|
||||
return errno;
|
||||
}
|
||||
*/
|
||||
if (argc == 4)
|
||||
mark = argv[3][0];
|
||||
|
||||
while (1)
|
||||
{
|
||||
size = read(fd1, &c, 1);
|
||||
if (size <= 0)
|
||||
break;
|
||||
|
||||
parse:
|
||||
if (c == 0x0d)
|
||||
{
|
||||
size = read(fd1, &c, 1);
|
||||
if (size <= 0)
|
||||
{
|
||||
out(0x0d);
|
||||
break;
|
||||
}
|
||||
if (c == 0x0a)
|
||||
{
|
||||
out(0x0a);
|
||||
}
|
||||
else
|
||||
{
|
||||
out(0x0d);
|
||||
goto parse;
|
||||
}
|
||||
}
|
||||
else
|
||||
out(c);
|
||||
}
|
||||
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
return 0;
|
||||
}
|
||||
close(fd1);
|
||||
close(fd2);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
> This utility is a unidirectional relay so you need to run two instances to get duplex communication, like:
|
||||
|
@ -49,7 +49,9 @@ Security Notes
|
||||
2. Select `Terminal Emulator`.
|
||||
3. In the window that opens, enter this command:
|
||||
|
||||
sudo nano /etc/yum.repos.d/qubes-dom0.repo
|
||||
```
|
||||
sudo nano /etc/yum.repos.d/qubes-dom0.repo
|
||||
```
|
||||
|
||||
4. This opens the nano text editor. Change all four instances of `http` to `https`.
|
||||
5. Press `CTRL+X`, then `Y`, then `ENTER` to save changes and exit.
|
||||
@ -61,8 +63,10 @@ Security Notes
|
||||
2. Select `Template: fedora-26`, then `fedora-26: Terminal`.
|
||||
3. In the window that opens, enter the command for your version:
|
||||
|
||||
[Qubes 3.2] sudo gedit /etc/yum.repos.d/qubes-r3.repo
|
||||
[Qubes 4.0] sudo gedit /etc/yum.repos.d/qubes-r4.repo
|
||||
```
|
||||
[Qubes 3.2] sudo gedit /etc/yum.repos.d/qubes-r3.repo
|
||||
[Qubes 4.0] sudo gedit /etc/yum.repos.d/qubes-r4.repo
|
||||
```
|
||||
|
||||
4. This opens the gedit text editor in a window. Change all four instances of `http` to `https`.
|
||||
5. Click the "Save" button in the top-right corner of the window.
|
||||
|
@ -23,13 +23,13 @@ Before passing user input, the socket service will receive a null-terminated ser
|
||||
When running in a VM, this is:
|
||||
|
||||
```
|
||||
<service_name> <source>\0
|
||||
<service_name> <source>\0
|
||||
```
|
||||
|
||||
When running in dom0, it is:
|
||||
|
||||
```
|
||||
<service_name> <source> <target_type> <target>\0
|
||||
<service_name> <source> <target_type> <target>\0
|
||||
```
|
||||
|
||||
(The target type can be `name`, in which case target is a domain name, or `keyword`, in which the target is a keyword like `@dispvm`).
|
||||
|
@ -33,7 +33,7 @@ the stdin/stdout/stderr from this remote process will be passed to the
|
||||
E.g., to start a primitive shell in a VM type the following in Dom0 console:
|
||||
|
||||
```shell_session
|
||||
[user@dom0 ~]$ /usr/lib/qubes/qrexec-client -d <vm name> user:bash
|
||||
[user@dom0 ~]$ /usr/lib/qubes/qrexec-client -d <vm name> user:bash
|
||||
```
|
||||
|
||||
The string before first semicolon specifies what user to run the command as.
|
||||
@ -102,21 +102,21 @@ whose names describe the available RPC actions; their content is the RPC
|
||||
access policy database. Some example of the default services in Qubes are:
|
||||
|
||||
```
|
||||
qubes.Filecopy
|
||||
qubes.OpenInVM
|
||||
qubes.ReceiveUpdates
|
||||
qubes.SyncAppMenus
|
||||
qubes.VMShell
|
||||
qubes.ClipboardPaste
|
||||
qubes.Gpg
|
||||
qubes.NotifyUpdates
|
||||
qubes.PdfConvert
|
||||
qubes.Filecopy
|
||||
qubes.OpenInVM
|
||||
qubes.ReceiveUpdates
|
||||
qubes.SyncAppMenus
|
||||
qubes.VMShell
|
||||
qubes.ClipboardPaste
|
||||
qubes.Gpg
|
||||
qubes.NotifyUpdates
|
||||
qubes.PdfConvert
|
||||
```
|
||||
|
||||
These files contain lines with the following format:
|
||||
|
||||
```
|
||||
srcvm destvm (allow|deny|ask)[,user=user_to_run_as][,target=VM_to_redirect_to]
|
||||
srcvm destvm (allow|deny|ask)[,user=user_to_run_as][,target=VM_to_redirect_to]
|
||||
```
|
||||
|
||||
You can specify `srcvm` and `destvm` by name, or by one of `$anyvm`,
|
||||
@ -142,7 +142,7 @@ name of the program that will be invoked.
|
||||
In a src VM, one should invoke the qrexec client via the following command:
|
||||
|
||||
```
|
||||
/usr/lib/qubes/qrexec-client-vm <target vm name> <service name> <local program path> [local program arguments]
|
||||
/usr/lib/qubes/qrexec-client-vm <target vm name> <service name> <local program path> [local program arguments]
|
||||
```
|
||||
|
||||
Note that only stdin/stdout is passed between RPC server and client --
|
||||
@ -176,7 +176,7 @@ In order to remove such authorization, issue this command from a Dom0 terminal
|
||||
(example below for `qubes.Filecopy` service):
|
||||
|
||||
```shell_session
|
||||
sudo nano /etc/qubes-rpc/policy/qubes.Filecopy
|
||||
sudo nano /etc/qubes-rpc/policy/qubes.Filecopy
|
||||
```
|
||||
|
||||
and then remove any line(s) ending in "allow" (before the first `##` comment)
|
||||
@ -193,37 +193,37 @@ integers on the target VM and returns back the result to the invoking VM.
|
||||
|
||||
* Client code on source VM (`/usr/bin/our_test_add_client`)
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
echo $1 $2 # pass data to rpc server
|
||||
exec cat >&$SAVED_FD_1 # print result to the original stdout, not to the other rpc endpoint
|
||||
```
|
||||
```bash
|
||||
#!/bin/sh
|
||||
echo $1 $2 # pass data to rpc server
|
||||
exec cat >&$SAVED_FD_1 # print result to the original stdout, not to the other rpc endpoint
|
||||
```
|
||||
|
||||
* Server code on target VM (`/usr/bin/our_test_add_server`)
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
read arg1 arg2 # read from stdin, which is received from the rpc client
|
||||
echo $(($arg1+$arg2)) # print to stdout - so, pass to the rpc client
|
||||
```
|
||||
```bash
|
||||
#!/bin/sh
|
||||
read arg1 arg2 # read from stdin, which is received from the rpc client
|
||||
echo $(($arg1+$arg2)) # print to stdout - so, pass to the rpc client
|
||||
```
|
||||
|
||||
* Policy file in dom0 (`/etc/qubes-rpc/policy/test.Add`)
|
||||
|
||||
```shell_session
|
||||
$anyvm $anyvm ask
|
||||
```
|
||||
```shell_session
|
||||
$anyvm $anyvm ask
|
||||
```
|
||||
|
||||
* Server path definition on target VM (`/etc/qubes-rpc/test.Add`)
|
||||
|
||||
```
|
||||
/usr/bin/our_test_add_server
|
||||
```
|
||||
```
|
||||
/usr/bin/our_test_add_server
|
||||
```
|
||||
|
||||
* To test this service, run the following in the source VM:
|
||||
|
||||
```
|
||||
/usr/lib/qubes/qrexec-client-vm <target VM> test.Add /usr/bin/our_test_add_client 1 2
|
||||
```
|
||||
```
|
||||
/usr/lib/qubes/qrexec-client-vm <target VM> test.Add /usr/bin/our_test_add_client 1 2
|
||||
```
|
||||
|
||||
and we should get "3" as answer, provided dom0 policy allows the call to pass
|
||||
through, which would happen after we click "Yes" in the popup that should
|
||||
|
@ -119,14 +119,14 @@ Each message starts with the following header:
|
||||
|
||||
```c
|
||||
struct msghdr {
|
||||
uint32_t type;
|
||||
uint32_t window;
|
||||
/* This field is intended for use by gui_agents to skip unknown
|
||||
* messages from the (trusted) guid. Guid, on the other hand,
|
||||
* should never rely on this field to calculate the actual len of
|
||||
* message to be read, as the (untrusted) agent can put here
|
||||
* whatever it wants! */
|
||||
uint32_t untrusted_len;
|
||||
uint32_t type;
|
||||
uint32_t window;
|
||||
/* This field is intended for use by gui_agents to skip unknown
|
||||
* messages from the (trusted) guid. Guid, on the other hand,
|
||||
* should never rely on this field to calculate the actual len of
|
||||
* message to be read, as the (untrusted) agent can put here
|
||||
* whatever it wants! */
|
||||
uint32_t untrusted_len;
|
||||
};
|
||||
```
|
||||
|
||||
@ -412,8 +412,8 @@ struct msg_focus {
|
||||
<td>MSG_WINDOW_FLAGS</td>
|
||||
<td><pre>
|
||||
struct msg_window_flags {
|
||||
uint32_t flags_set;
|
||||
uint32_t flags_unset;
|
||||
uint32_t flags_set;
|
||||
uint32_t flags_unset;
|
||||
};
|
||||
</pre> </td>
|
||||
<td>Window state change confirmation</td>
|
||||
|
@ -46,13 +46,13 @@ The feature can be enabled on any network-providing qube, and will be propagated
|
||||
To enable the `ipv6` feature use `qvm-features` tool and set the value to `1`. For example to enable it on `sys-net`, execute in dom0:
|
||||
|
||||
```
|
||||
qvm-features sys-net ipv6 1
|
||||
qvm-features sys-net ipv6 1
|
||||
```
|
||||
|
||||
It is also possible to explicitly disable IPv6 support for some qubes, even if it is connected to IPv6-providing one. This can be done by setting `ipv6` feature to empty value:
|
||||
|
||||
```
|
||||
qvm-features ipv4-only-qube ipv6 ''
|
||||
qvm-features ipv4-only-qube ipv6 ''
|
||||
```
|
||||
|
||||
This configuration is presented below - green qubes have IPv6 access, red one does not.
|
||||
|
@ -42,91 +42,91 @@ rationale in an
|
||||
to the Qubes mailing lists:
|
||||
|
||||
```
|
||||
Hello,
|
||||
Hello,
|
||||
|
||||
A new Qubes Security Bulletin has been just released and is available here:
|
||||
A new Qubes Security Bulletin has been just released and is available here:
|
||||
|
||||
https://github.com/QubesOS/qubes-secpack/blob/master/QSBs/qsb-013-2015.txt
|
||||
https://github.com/QubesOS/qubes-secpack/blob/master/QSBs/qsb-013-2015.txt
|
||||
|
||||
As per the previous discussions about recent problems with verifying
|
||||
digital signatures on messages sent to Google Groups (thanks to
|
||||
automatic footer addition by Google), we have decided to change the way
|
||||
we publish Qubes Security Bulletins, as well as other security-related
|
||||
info pertinent to the Qubes Project.
|
||||
As per the previous discussions about recent problems with verifying
|
||||
digital signatures on messages sent to Google Groups (thanks to
|
||||
automatic footer addition by Google), we have decided to change the way
|
||||
we publish Qubes Security Bulletins, as well as other security-related
|
||||
info pertinent to the Qubes Project.
|
||||
|
||||
Starting today, we will be maintain a Git repository -- "Qubes Security
|
||||
Pack" -- which will contain all the QSBs released so far, all the keys,
|
||||
warrant canaries [1], and potentially some additional info or
|
||||
announcements (e.g. key revocations). The whole repo can be found here:
|
||||
Starting today, we will be maintain a Git repository -- "Qubes Security
|
||||
Pack" -- which will contain all the QSBs released so far, all the keys,
|
||||
warrant canaries [1], and potentially some additional info or
|
||||
announcements (e.g. key revocations). The whole repo can be found here:
|
||||
|
||||
https://github.com/QubesOS/qubes-secpack
|
||||
https://github.com/QubesOS/qubes-secpack
|
||||
|
||||
Note that all the keys distributed there should be signed by Qubes
|
||||
Master Key. The Master Key is also attached in the repo, but should
|
||||
really be obtained/verified using a different channel.
|
||||
Note that all the keys distributed there should be signed by Qubes
|
||||
Master Key. The Master Key is also attached in the repo, but should
|
||||
really be obtained/verified using a different channel.
|
||||
|
||||
Additionally, most of the files are signed by core Qubes
|
||||
developers (currently by Marek and myself) via detached signatures as
|
||||
well as git tag signatures.
|
||||
Additionally, most of the files are signed by core Qubes
|
||||
developers (currently by Marek and myself) via detached signatures as
|
||||
well as git tag signatures.
|
||||
|
||||
The are several advantages of using Git to distribute all these information:
|
||||
The are several advantages of using Git to distribute all these information:
|
||||
|
||||
1) Git repo is a collection of files, some of which can be detached GPG
|
||||
signatures for other files and we can ensure all these files are
|
||||
distributed together.
|
||||
1) Git repo is a collection of files, some of which can be detached GPG
|
||||
signatures for other files and we can ensure all these files are
|
||||
distributed together.
|
||||
|
||||
2) Git makes it easy for people to clone and redistribute these
|
||||
collection of files, as well as to easily host them and view on the Web.
|
||||
2) Git makes it easy for people to clone and redistribute these
|
||||
collection of files, as well as to easily host them and view on the Web.
|
||||
|
||||
3) Git provides for signed tags mechanisms which is another mean we
|
||||
utilize to ensure integrity of the distributed files.
|
||||
3) Git provides for signed tags mechanisms which is another mean we
|
||||
utilize to ensure integrity of the distributed files.
|
||||
|
||||
A few words about the Warrant Canary which we've just introduced today,
|
||||
and which can be seen here:
|
||||
A few words about the Warrant Canary which we've just introduced today,
|
||||
and which can be seen here:
|
||||
|
||||
https://github.com/QubesOS/qubes-secpack/blob/master/canaries/canary-001-2015.txt
|
||||
https://github.com/QubesOS/qubes-secpack/blob/master/canaries/canary-001-2015.txt
|
||||
|
||||
Even though we're not providing any kind of services (such as e.g. email
|
||||
hosting), that could be searched or tapped by authorities, there are
|
||||
other possibilities that worry us [2], in the light of various recent
|
||||
law "developments", such as those that might be coercing people to hand
|
||||
over their private keys to authorities.
|
||||
Even though we're not providing any kind of services (such as e.g. email
|
||||
hosting), that could be searched or tapped by authorities, there are
|
||||
other possibilities that worry us [2], in the light of various recent
|
||||
law "developments", such as those that might be coercing people to hand
|
||||
over their private keys to authorities.
|
||||
|
||||
Until we fully decentralize the root of trust for Qubes, something that
|
||||
requires the move to deterministic builds [3], and so won't happen
|
||||
very soon, the possibility of having to disclose any of the Qubes
|
||||
signing keys to anybody might have pretty serious consequences for those
|
||||
who decided to entrust Qubes with anything serious. And we would like to
|
||||
somehow minimize these consequences with this canary thing.
|
||||
Until we fully decentralize the root of trust for Qubes, something that
|
||||
requires the move to deterministic builds [3], and so won't happen
|
||||
very soon, the possibility of having to disclose any of the Qubes
|
||||
signing keys to anybody might have pretty serious consequences for those
|
||||
who decided to entrust Qubes with anything serious. And we would like to
|
||||
somehow minimize these consequences with this canary thing.
|
||||
|
||||
Additionally the canary is a nice way of ensuring "freshness" of our
|
||||
messaging to the community.
|
||||
Additionally the canary is a nice way of ensuring "freshness" of our
|
||||
messaging to the community.
|
||||
|
||||
Of course the canary doesn't solve all the problems. E.g. if my signing
|
||||
keys were somehow stolen without our knowledge, it wouldn't help.
|
||||
Neither it could help in case me being or becoming a miscreant. And
|
||||
probably it doesn't address many other potential problems, which could
|
||||
only be solved one day with a multi-signature scheme. But anyway, until
|
||||
that time, this is the best we can do, I think.
|
||||
Of course the canary doesn't solve all the problems. E.g. if my signing
|
||||
keys were somehow stolen without our knowledge, it wouldn't help.
|
||||
Neither it could help in case me being or becoming a miscreant. And
|
||||
probably it doesn't address many other potential problems, which could
|
||||
only be solved one day with a multi-signature scheme. But anyway, until
|
||||
that time, this is the best we can do, I think.
|
||||
|
||||
And congrats to Jann for the very interesting clipboard attack (even
|
||||
though mostly theoretical, still very cool)!
|
||||
And congrats to Jann for the very interesting clipboard attack (even
|
||||
though mostly theoretical, still very cool)!
|
||||
|
||||
Thanks,
|
||||
joanna.
|
||||
Thanks,
|
||||
joanna.
|
||||
|
||||
--
|
||||
The Qubes Security Team
|
||||
https://www.qubes-os.org/doc/SecurityPage
|
||||
--
|
||||
The Qubes Security Team
|
||||
https://www.qubes-os.org/doc/SecurityPage
|
||||
|
||||
|
||||
[1] http://en.wikipedia.org/wiki/Warrant_canary
|
||||
[1] http://en.wikipedia.org/wiki/Warrant_canary
|
||||
|
||||
[2] Especially myself, because I'm currently the Root Of Trust for all
|
||||
Qubes binaries :/
|
||||
[2] Especially myself, because I'm currently the Root Of Trust for all
|
||||
Qubes binaries :/
|
||||
|
||||
[3] Deterministic builds are required because it's the only way we can
|
||||
implement multiple signature scheme for distributed binaries.
|
||||
[3] Deterministic builds are required because it's the only way we can
|
||||
implement multiple signature scheme for distributed binaries.
|
||||
|
||||
```
|
||||
|
||||
|
@ -32,13 +32,17 @@ Inside the TemplateBasedVM.
|
||||
|
||||
1. Make sure folder `/rw/config/qubes-bind-dirs.d` exists.
|
||||
|
||||
sudo mkdir -p /rw/config/qubes-bind-dirs.d
|
||||
```
|
||||
sudo mkdir -p /rw/config/qubes-bind-dirs.d
|
||||
```
|
||||
|
||||
2. Create a file `/rw/config/qubes-bind-dirs.d/50_user.conf` with root rights.
|
||||
|
||||
3. Edit the file 50_user.conf to append a folder or file name to the `binds` variable.
|
||||
|
||||
binds+=( '/var/lib/tor' )
|
||||
```
|
||||
binds+=( '/var/lib/tor' )
|
||||
```
|
||||
|
||||
4. Save.
|
||||
|
||||
|
@ -73,9 +73,11 @@ state of the system with the administrator's configuration/desires.
|
||||
The smallest unit of configuration is a state.
|
||||
A state is written in YAML and looks like this:
|
||||
|
||||
stateid:
|
||||
cmd.run: #this is the execution module. in this case it will execute a command on the shell
|
||||
- name: echo 'hello world' #this is a parameter of the state.
|
||||
```
|
||||
stateid:
|
||||
cmd.run: #this is the execution module. in this case it will execute a command on the shell
|
||||
- name: echo 'hello world' #this is a parameter of the state.
|
||||
```
|
||||
|
||||
The stateid has to be unique throughout all states running for a minion and can
|
||||
be used to order the execution of the references state.
|
||||
@ -96,24 +98,26 @@ With these three states you can define most of the configuration of a VM.
|
||||
|
||||
You can also [order the execution][salt-doc-states-order] of your states:
|
||||
|
||||
D:
|
||||
cmd.run:
|
||||
- name: echo 1
|
||||
- order: last
|
||||
C:
|
||||
cmd.run:
|
||||
- name: echo 1
|
||||
B:
|
||||
cmd.run:
|
||||
- name: echo 1
|
||||
- require:
|
||||
- cmd: A
|
||||
- require_in:
|
||||
- cmd:C
|
||||
A:
|
||||
cmd.run:
|
||||
- name: echo 1
|
||||
- order: 1
|
||||
```
|
||||
D:
|
||||
cmd.run:
|
||||
- name: echo 1
|
||||
- order: last
|
||||
C:
|
||||
cmd.run:
|
||||
- name: echo 1
|
||||
B:
|
||||
cmd.run:
|
||||
- name: echo 1
|
||||
- require:
|
||||
- cmd: A
|
||||
- require_in:
|
||||
- cmd:C
|
||||
A:
|
||||
cmd.run:
|
||||
- name: echo 1
|
||||
- order: 1
|
||||
```
|
||||
|
||||
The order of execution will be `A, B, C, D`.
|
||||
The official documentation has more details on the
|
||||
@ -132,10 +136,12 @@ After you have several state files, you need something to assign them to a VM.
|
||||
This is done by `*.top` files ([official documentation][salt-doc-top]).
|
||||
Their structure looks like this:
|
||||
|
||||
environment:
|
||||
target_matching_clause:
|
||||
- statefile1
|
||||
- folder2.statefile2
|
||||
```
|
||||
environment:
|
||||
target_matching_clause:
|
||||
- statefile1
|
||||
- folder2.statefile2
|
||||
```
|
||||
|
||||
In most cases, the environment will be called `base`.
|
||||
The `target_matching_clause` will be used to select your minions (VMs).
|
||||
@ -143,10 +149,12 @@ It can be either the name of a VM or a regular expression.
|
||||
If you are using a regular expressions, you need to give Salt a hint you are
|
||||
doing so:
|
||||
|
||||
environment:
|
||||
^app-(work|(?!mail).*)$:
|
||||
- match: pcre
|
||||
- statefile
|
||||
```
|
||||
environment:
|
||||
^app-(work|(?!mail).*)$:
|
||||
- match: pcre
|
||||
- statefile
|
||||
```
|
||||
|
||||
For each target you can write a list of state files.
|
||||
Each line is a path to a state file (without the `.sls` extension) relative to
|
||||
@ -220,23 +228,25 @@ You can also use the `qubes` pillar module to select VMs with a particular
|
||||
property (see below).
|
||||
If you do so, then you need to pass additional arguments to the `qubesctl` tool:
|
||||
|
||||
usage: qubesctl [-h] [--show-output] [--force-color] [--skip-dom0]
|
||||
[--targets TARGETS | --templates | --app | --all]
|
||||
...
|
||||
```
|
||||
usage: qubesctl [-h] [--show-output] [--force-color] [--skip-dom0]
|
||||
[--targets TARGETS | --templates | --app | --all]
|
||||
...
|
||||
|
||||
positional arguments:
|
||||
command Salt command to execute (e.g., state.highstate)
|
||||
positional arguments:
|
||||
command Salt command to execute (e.g., state.highstate)
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--show-output Show output of management commands
|
||||
--force-color Force color output, allow control characters from VM,
|
||||
UNSAFE
|
||||
--skip-dom0 Skip dom0 configuration (VM creation etc)
|
||||
--targets TARGETS Coma separated list of VMs to target
|
||||
--templates Target all templates
|
||||
--app Target all AppVMs
|
||||
--all Target all non-disposable VMs (TemplateVMs and AppVMs)
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--show-output Show output of management commands
|
||||
--force-color Force color output, allow control characters from VM,
|
||||
UNSAFE
|
||||
--skip-dom0 Skip dom0 configuration (VM creation etc)
|
||||
--targets TARGETS Coma separated list of VMs to target
|
||||
--templates Target all templates
|
||||
--app Target all AppVMs
|
||||
--all Target all non-disposable VMs (TemplateVMs and AppVMs)
|
||||
```
|
||||
|
||||
To apply a state to all templates, call `qubesctl --templates state.highstate`.
|
||||
|
||||
@ -269,15 +279,17 @@ Beginning with Qubes 4.0 and after [QSB #45], we implemented two changes:
|
||||
|
||||
Let's start with a quick example:
|
||||
|
||||
my new and shiny VM:
|
||||
qvm.present:
|
||||
- name: salt-test # can be omitted when same as ID
|
||||
- template: fedora-21
|
||||
- label: yellow
|
||||
- mem: 2000
|
||||
- vcpus: 4
|
||||
- flags:
|
||||
- proxy
|
||||
```
|
||||
my new and shiny VM:
|
||||
qvm.present:
|
||||
- name: salt-test # can be omitted when same as ID
|
||||
- template: fedora-21
|
||||
- label: yellow
|
||||
- mem: 2000
|
||||
- vcpus: 4
|
||||
- flags:
|
||||
- proxy
|
||||
```
|
||||
|
||||
It uses the Qubes-specific `qvm.present` state, which ensures that the domain is
|
||||
present (if not, it creates it).
|
||||
@ -297,9 +309,11 @@ As you will notice, the options are the same (or very similar) to those used in
|
||||
This should be put in `/srv/salt/my-new-vm.sls` or another `.sls` file.
|
||||
A separate `*.top` file should be also written:
|
||||
|
||||
base:
|
||||
dom0:
|
||||
- my-new-vm
|
||||
```
|
||||
base:
|
||||
dom0:
|
||||
- my-new-vm
|
||||
```
|
||||
|
||||
**Note** The third line should contain the name of the previous state file,
|
||||
without the `.sls` extension.
|
||||
@ -322,15 +336,19 @@ Lets make sure that the `mc` package is installed in all templates.
|
||||
Similar to the previous example, you need to create a state file
|
||||
(`/srv/salt/mc-everywhere.sls`):
|
||||
|
||||
mc:
|
||||
pkg.installed: []
|
||||
```
|
||||
mc:
|
||||
pkg.installed: []
|
||||
```
|
||||
|
||||
Then the appropriate top file (`/srv/salt/mc-everywhere.top`):
|
||||
|
||||
base:
|
||||
qubes:type:template:
|
||||
- match: pillar
|
||||
- mc-everywhere
|
||||
```
|
||||
base:
|
||||
qubes:type:template:
|
||||
- match: pillar
|
||||
- mc-everywhere
|
||||
```
|
||||
|
||||
Now you need to enable the top file:
|
||||
|
||||
@ -354,27 +372,31 @@ As in the example above, it creates a domain and sets its properties.
|
||||
|
||||
You can set properties of an existing domain:
|
||||
|
||||
my preferences:
|
||||
qvm.prefs:
|
||||
- name: salt-test2
|
||||
- netvm: sys-firewall
|
||||
```
|
||||
my preferences:
|
||||
qvm.prefs:
|
||||
- name: salt-test2
|
||||
- netvm: sys-firewall
|
||||
```
|
||||
|
||||
***Note*** The `name:` option will not change the name of a domain, it will only
|
||||
be used to match a domain to apply the configurations to it.
|
||||
|
||||
### `qvm.service`
|
||||
|
||||
services in my domain:
|
||||
qvm.service:
|
||||
- name: salt-test3
|
||||
- enable:
|
||||
- service1
|
||||
- service2
|
||||
- disable:
|
||||
- service3
|
||||
- service4
|
||||
- default:
|
||||
- service5
|
||||
```
|
||||
services in my domain:
|
||||
qvm.service:
|
||||
- name: salt-test3
|
||||
- enable:
|
||||
- service1
|
||||
- service2
|
||||
- disable:
|
||||
- service3
|
||||
- service4
|
||||
- default:
|
||||
- service5
|
||||
```
|
||||
|
||||
This enables, disables, or sets to default, services as in `qvm-service`.
|
||||
|
||||
@ -382,9 +404,11 @@ This enables, disables, or sets to default, services as in `qvm-service`.
|
||||
|
||||
Ensures the specified domain is running:
|
||||
|
||||
domain is running:
|
||||
qvm.running:
|
||||
- name: salt-test4
|
||||
```
|
||||
domain is running:
|
||||
qvm.running:
|
||||
- name: salt-test4
|
||||
```
|
||||
|
||||
## Virtual Machine Formulae
|
||||
|
||||
@ -567,9 +591,11 @@ Having the `-p` flag is important when using a state with `cmd.run`.
|
||||
If you install multiple templates you may encounter this error.
|
||||
The solution is to shut down the updateVM between each install:
|
||||
|
||||
install template and shutdown updateVM:
|
||||
cmd.run:
|
||||
- name: sudo qubes-dom0-update -y fedora-24; qvm-shutdown {% raw %}{{ salt.cmd.run(qubes-prefs updateVM) }}{% endraw %}
|
||||
```
|
||||
install template and shutdown updateVM:
|
||||
cmd.run:
|
||||
- name: sudo qubes-dom0-update -y fedora-24; qvm-shutdown {% raw %}{{ salt.cmd.run(qubes-prefs updateVM) }}{% endraw %}
|
||||
```
|
||||
|
||||
## Further Reading
|
||||
|
||||
|
@ -30,10 +30,12 @@ When backing up dom0 using the Qubes backup tool (explained below), only the hom
|
||||
Therefore, if there are files outside of the home directory you wish to save, you should copy them into the home directory prior to creating a backup.
|
||||
Here is an example of how to back up Qubes config files and RPC policies:
|
||||
|
||||
$ mkdir -p ~/backup/etc/qubes/
|
||||
$ cp -a /etc/qubes/* ~/backup/etc/qubes/
|
||||
$ mkdir ~/backup/etc/qubes-rpc/
|
||||
$ cp -a /etc/qubes-rpc/* ~/systemfiles/etc/qubes-rpc/
|
||||
```
|
||||
$ mkdir -p ~/backup/etc/qubes/
|
||||
$ cp -a /etc/qubes/* ~/backup/etc/qubes/
|
||||
$ mkdir ~/backup/etc/qubes-rpc/
|
||||
$ cp -a /etc/qubes-rpc/* ~/systemfiles/etc/qubes-rpc/
|
||||
```
|
||||
|
||||
To restore these files, move them from the restored directory in dom0's home back to their appropriate locations in `/etc/`.
|
||||
Please note that any packages installed via the package manager in dom0 will not be backed up.
|
||||
|
@ -15,51 +15,53 @@ Passwordless Root Access in VMs
|
||||
|
||||
Background (`/etc/sudoers.d/qubes` in VM):
|
||||
|
||||
user ALL=(ALL) NOPASSWD: ALL
|
||||
```
|
||||
user ALL=(ALL) NOPASSWD: ALL
|
||||
|
||||
# WTF?! Have you lost your mind?!
|
||||
#
|
||||
# In Qubes VMs there is no point in isolating the root account from
|
||||
# the user account. This is because all the user data is already
|
||||
# accessible from the user account, so there is no direct benefit for
|
||||
# the attacker if she could escalate to root (there is even no benefit
|
||||
# in trying to install some persistent rootkits, as the VM's root
|
||||
# filesystem modifications are lost upon each start of a VM).
|
||||
#
|
||||
# One might argue that some hypothetical attacks against the
|
||||
# hypervisor or the few daemons/backends in Dom0 (so VM escape
|
||||
# attacks) most likely would require root access in the VM to trigger
|
||||
# the attack.
|
||||
#
|
||||
# That's true, but mere existence of such a bug in the hypervisor or
|
||||
# Dom0 that could be exploited by a malicious VM, no matter whether
|
||||
# requiring user, root, or even kernel access in the VM, would be
|
||||
# FATAL. In such situation (if there was such a bug in Xen) there
|
||||
# really is no comforting that: "oh, but the mitigating factor was
|
||||
# that the attacker needed root in VM!" We're not M$, and we're not
|
||||
# gonna BS our users that there are mitigating factors in that case,
|
||||
# and for sure, root/user isolation is not a mitigating factor.
|
||||
#
|
||||
# Because, really, if somebody could find and exploit a bug in the Xen
|
||||
# hypervisor -- as of 2016, there have been only three publicly disclosed
|
||||
# exploitable bugs in the Xen hypervisor from a VM -- then it would be
|
||||
# highly unlikely if that person couldn't also found a user-to-root
|
||||
# escalation in VM (which as we know from history of UNIX/Linux
|
||||
# happens all the time).
|
||||
#
|
||||
# At the same time allowing for easy user-to-root escalation in a VM
|
||||
# is simply convenient for users, especially for update installation.
|
||||
#
|
||||
# Currently this still doesn't work as expected, because some idotic
|
||||
# piece of software called PolKit uses own set of policies. We're
|
||||
# planning to address this in Beta 2. (Why PolKit is an idiocy? Do a
|
||||
# simple experiment: start 'xinput test' in one xterm, running as
|
||||
# user, then open some app that uses PolKit and asks for root
|
||||
# password, e.g. gpk-update-viewer -- observe how all the keystrokes
|
||||
# with root password you enter into the "secure" PolKit dialog box can
|
||||
# be seen by the xinput program...)
|
||||
#
|
||||
# joanna.
|
||||
# WTF?! Have you lost your mind?!
|
||||
#
|
||||
# In Qubes VMs there is no point in isolating the root account from
|
||||
# the user account. This is because all the user data is already
|
||||
# accessible from the user account, so there is no direct benefit for
|
||||
# the attacker if she could escalate to root (there is even no benefit
|
||||
# in trying to install some persistent rootkits, as the VM's root
|
||||
# filesystem modifications are lost upon each start of a VM).
|
||||
#
|
||||
# One might argue that some hypothetical attacks against the
|
||||
# hypervisor or the few daemons/backends in Dom0 (so VM escape
|
||||
# attacks) most likely would require root access in the VM to trigger
|
||||
# the attack.
|
||||
#
|
||||
# That's true, but mere existence of such a bug in the hypervisor or
|
||||
# Dom0 that could be exploited by a malicious VM, no matter whether
|
||||
# requiring user, root, or even kernel access in the VM, would be
|
||||
# FATAL. In such situation (if there was such a bug in Xen) there
|
||||
# really is no comforting that: "oh, but the mitigating factor was
|
||||
# that the attacker needed root in VM!" We're not M$, and we're not
|
||||
# gonna BS our users that there are mitigating factors in that case,
|
||||
# and for sure, root/user isolation is not a mitigating factor.
|
||||
#
|
||||
# Because, really, if somebody could find and exploit a bug in the Xen
|
||||
# hypervisor -- as of 2016, there have been only three publicly disclosed
|
||||
# exploitable bugs in the Xen hypervisor from a VM -- then it would be
|
||||
# highly unlikely if that person couldn't also found a user-to-root
|
||||
# escalation in VM (which as we know from history of UNIX/Linux
|
||||
# happens all the time).
|
||||
#
|
||||
# At the same time allowing for easy user-to-root escalation in a VM
|
||||
# is simply convenient for users, especially for update installation.
|
||||
#
|
||||
# Currently this still doesn't work as expected, because some idotic
|
||||
# piece of software called PolKit uses own set of policies. We're
|
||||
# planning to address this in Beta 2. (Why PolKit is an idiocy? Do a
|
||||
# simple experiment: start 'xinput test' in one xterm, running as
|
||||
# user, then open some app that uses PolKit and asks for root
|
||||
# password, e.g. gpk-update-viewer -- observe how all the keystrokes
|
||||
# with root password you enter into the "secure" PolKit dialog box can
|
||||
# be seen by the xinput program...)
|
||||
#
|
||||
# joanna.
|
||||
```
|
||||
|
||||
Below is a complete list of configuration made according to the above statement, with (not necessary complete) list of mechanisms depending on each of them:
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user