Compare commits

..

62 Commits

Author SHA1 Message Date
Jan Höppner
1bb9a9ec5b New release s390-tools-2.16.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 15:46:37 +01:00
Nikita Dubrovskii
4a3957fab5 zipl: fix reading 4k disk's geometry
On 4k SCSI disks zipl stores wrong values to 'scsi_mbr.program_table_pointer',
which makes system unbootable.
This happens in 'zipl/src/disk.c:656':

```
/* Convert file system block to physical */
*physical = mapped * phy_per_fs + subblock;
/* Add partition start */
*physical += info->geo.start;

```

So 'hd_geometry.start' should be adjusted before being used.

Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1918723
Closes: https://github.com/ibm-s390-linux/s390-tools/pull/107
Signed-off-by: Nikita Dubrovskii <nikita@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:47:07 +01:00
Ingo Franzki
e506c94839 zkey-ekmfweb: Fix typos in messages
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:47:07 +01:00
Wenjia Zhang
dfd9f52873 hsci: fix packet loss caused by large MTU
For maximum performance the MTU of an HSCI interface was set to the value
of the MTU of its HiperSockets interface. However, the MTU of a
HiperSockets interface can be very large, and when the data packets are
not sent over the HiperSocket but over the corresponding ethernet
interface (which usually has a smaller MTU size) then it can happen that
the large packets are silently dropped. One example would be communication
from an HSCI in one CEC to another HSCI in another CEC via Ethernet.

To solve the problem, the MTU setting in this tool is removed, and the
default MTU value is used. Thus, the minimum value of the MTUs of the both
converged interfaces is used as the MTU of the HSCI interface.

Fixes: 0566a492ae ("s390-tools: add hsci tool")
Signed-off-by: Wenjia Zhang <wenjia@linux.ibm.com>
Reviewed-by: Alexandra Winter <wintera@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:47:07 +01:00
Jan Höppner
14ca7c5080 s390-tools: Change GitHub link to new name
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:47:07 +01:00
Steffen Maier
4fc1a92a8d zfcpdbf: deal with crash 7.2.9 change in caller name formatting
Since crash 7.2.9 commit
f1f43bf355
in support of kernel v5.9 commit 0990d836cecb
("s390/debug: debug feature version 3"),
the symbolic caller function name is left aligned instead of right
aligned, so now we alternatively have to remove whitespace between
function name and offset.

Otherwise, zfcpdbf output contains wrong warnings about ambiguous payload
records with wrong values for reqid and area, as well as incorrectly
decoded trace records with wrong content values and potential error
messages on not defined record id, and finally a potential list of
occurrences of unknown tags which should empty:

Loading trace records ...(this might take a while)
Warning: Ambiguous PAYload records. reqid:>>>wrong<<< area:V^D^@fcp_
Warning: Ambiguous PAYload records. reqid:>>>wrong<<< area:W^D^@fsf_
Warning: Ambiguous PAYload records. reqid:>>>wrong<<< area:i^B^@san_

...

Timestamp      : ...
Area           : SAN
Subarea        : 00
Level          : 1
Exception      : -
CPU ID         : 0001
Caller         : <zfcp_dbf_san_in_els
Record ID      : 0
Tag            : 6^B^Cfcie
Request ID     : >>>wrong<<<
Destination ID : >>>wrong<<<
SAN record id=0 not defined.
Timestamp      : ...
Area           : SAN
Subarea        : 00
Level          : 1
Exception      : -
CPU ID         : 0002
Caller         : <zfcp_dbf_san_in_els
Record ID      : 0
Tag            : 6^B^Cfcie
Request ID     : >>>wrong<<<
Destination ID : >>>wrong<<<
SAN record id=0 not defined.

...

occurrences of unknown tags:
...

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:46:54 +01:00
Ingo Franzki
d73d7f91ac zkey-ekmfweb: Fix typos in man page
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Alexander Egorenkov
800df6bef8 zipl/boot: fix heap OOM in stage2 of DASD dumper
For the stage2 of zipl's boot loaders only 3 heap pages are available
[0x6000, 0x6000 + 0x3000]. Therefore, stage2 code needs to be very careful
when and for how long it allocates a heap page.

The heap OOM problem in stage2 was hidden until the commit 252be376
("zipl/boot: fix potential heap overflow in stage2"). Before this commit,
stage2 assumed that heap is 4 pages large which is apparently very wrong
but get_zeroed_page() still allowed allocating an extra 4th page by
overriding the memory segment following the heap area of stage2 (stage3
parameter area).

Try to avoid allocating a heap page and keeping it allocated over a long
period of time in the DASD dumpers. Free a heap page as soon as possible
if not required anymore.

And be extra careful with printf() because it always tries to allocate
a free heap page.

Fixes: 252be376 ("zipl/boot: fix potential heap overflow in stage2")
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Marc Hartmayer
3c661da4ee genprotimg: boot: make boot loader -march=z900 compatible
Replace the `lgfi` opcode with equivalents as z900 has no support for
it.

While at it, fix a comment in `genprotimg/boot/head.S` and remove a
useless label in `genprotimg/boot/stage3b_reloc.S`.

Closes: https://github.com/ibm-s390-tools/s390-tools/issues/86
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Ingo Franzki
bf5ca4367d libekmfweb: Check length of JWK EC public key coordinates
RFC 7517 requires that the x and y coordinates of a ECC JSON Web Key
(JWK) are specified in its full size of a coordinate for the curve used.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Wenjia Zhang
faf26220a7 hsci: fix failed to delete an HSCI connected with VLAN
Deleting an HSCI interface, the connected HiperSockets interface's name
and the connected Ethernet interface's name are extracted from "ip link
show". Currently the extracted names are directly used in "bridge -d link
show dev ifname" for further checking. If "iflink" and "ifindex" of an
interface are not matched, ip commands will print @ifXX appended to the
real interface's name. Thus, it will be failed if the interface's name
with the ending @ifXX is used in "bridge -d link show dev ifname" for
further checking.

To solve the problem, the ending @ifXX must be removed before the
interface name is used further.

Signed-off-by: Wenjia Zhang <wenjia@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Wenjia Zhang
522252d18a hsci: fix wrong return code
In the current code, after the function check_pnetids() and the function
verify_precon() are called, $? from each function is used twice
successively. It is used for the first time in the condition of the IF
statement, while for the second time as return code of the current
function. In bash, $? can be used to get the return code, but only for
the first time directly after the previous function is called.
Afterwards, $? will be reset to "0". Thus, the right return code can not
be get, if $? is used second time.

To solve the problem, using $? for the second time should be avoided.

Signed-off-by: Wenjia Zhang <wenjia@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Alexander Egorenkov
42889edc0c make: add address sanitizer support
Install libasan first, e.g. on Fedora 32:
  dnf install -y libasan libasan-static.

To compile with address sanitizer, pass ASAN=1 to make.
AdressSanitizer helps to catch various memory bugs for which C/C++ is
infamous.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Alexander Egorenkov
13016ebc5a cmsfs-fuse: ASAN fix dec_to_hex() and hex_to_dec()
This fixes the following compiler errors when ASAN is enabled:

  CC      cmsfs-fuse/cmsfs-fuse.o
cmsfs-fuse.c: Assembler messages:
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:310: Error: operand out of range (0xffffffffffffff00 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:302: Error: operand out of range (0xfffffffffffffda0 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:302: Error: operand out of range (0xfffffffffffffda0 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:302: Error: operand out of range (0xfffffffffffffda0 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:302: Error: operand out of range (0xfffffffffffffda0 is not between 0x0000000000000000 and 0x0000000000000fff)
cmsfs-fuse.c:302: Error: operand out of range (0xfffffffffffffda0 is not between 0x0000000000000000 and 0x0000000000000fff)

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-02-19 13:43:41 +01:00
Ingo Franzki
c4546daf34 zkey-ekmfweb: Avoid sequence number clash when generating keys
When keys are generated concurrently in EKMF Web from multiple clients,
and the key labels use a sequence number tag, then the assignment logic
of the sequence number may cause a duplicate sequence number to be used,
because another key might have already been generated with the same
sequence number, since the next-to-use sequence number has been retrieved
from EKMF Web. This results in a HTTP response code of 409 and a -EEXIST
return code from ekmf_generate_key().

Instead of getting the last used sequence number from EKMFWeb, tell
EKMFWeb to automatically use the next available sequence number when
generating a key. When the sequence number label tag value is 'next'
then EKMFWeb will automatically assign the next available sequence number
to the label tag and increment the sequence number in an atomic way.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Alexander Egorenkov
1e18429f69 zdump: fix invalid memory access on memory chunk's data
If a memory chunk is added to mem_phys as well as mem_virt
in dfi_mem_chunk_add_vol() then an illegal memory access might occur
when accessing mem_chunk->data e.g. in dfi_elf_mem_chunk_read_fn()
because the data block pointed to by the data field is now being referenced
by two memory chunks, one in mem_phys and one in mem_virt. If it happens
that the memory chunk from mem_virt is freed in mem_unmap() then
the memory chunk in mem_phys still points to the common data block
which has been already freed. This leads to all sort of bad behavior
in dfi_elf_mem_chunk_read_fn() and other places where mem_chunk->data
might be accessed.

Fixes the following bug:
zgetdump: Unexpected end of file for "dump.all.elf"

And this was found by AddressSanitizer:

=================================================================
==81170==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000570 at pc 0x00000101ac10 bp 0x03ffd897e250 sp 0x03ffd897e248
READ of size 8 at 0x602000000570 thread T0
    #0 0x101ac0f in dfi_elf_mem_chunk_read_fn s390-tools/zdump/dfi_elf.c:27
    #1 0x100d8a5 in mem_read s390-tools/zdump/dfi.c:339
    #2 0x100d8a5 in dfi_mem_phys_read s390-tools/zdump/dfi.c:616
    #3 0x100d8a5 in mem_chunk_map_read_fn s390-tools/zdump/dfi.c:353
    #4 0x100fd29 in mem_read s390-tools/zdump/dfi.c:339
    #5 0x100fd29 in dfi_mem_read s390-tools/zdump/dfi.c:608
    #6 0x1018e89 in os_info_get s390-tools/zdump/dfi_vmcoreinfo.c:65
    #7 0x1018e89 in dfi_vmcoreinfo_init s390-tools/zdump/dfi_vmcoreinfo.c:86
    #8 0x10175b3 in dfi_init s390-tools/zdump/dfi.c:1215
    #9 0x1006e71 in do_stdout s390-tools/zdump/zgetdump.c:161
    #10 0x1006e71 in main s390-tools/zdump/zgetdump.c:180
    #11 0x3ffb07abb89 in __libc_start_main (/lib64/libc.so.6+0x2bb89)
    #12 0x1007e8d  (s390-tools/zdump/zgetdump+0x1007e8d)

0x602000000570 is located 0 bytes inside of 8-byte region [0x602000000570,0x602000000578)
freed by thread T0 here:
    #0 0x3ffb0bc961b in free (/lib64/libasan.so.6+0xc961b)
    #1 0x100d2d9 in mem_unmap s390-tools/zdump/dfi.c:1050

previously allocated by thread T0 here:
    #0 0x3ffb0bc9aa9 in calloc (/lib64/libasan.so.6+0xc9aa9)
    #1 0x100a271 in zg_alloc s390-tools/zdump/zg.c:93

SUMMARY: AddressSanitizer: heap-use-after-free s390-tools/zdump/dfi_elf.c:27 in dfi_elf_mem_chunk_read_fn
Shadow bytes around the buggy address:
  0x100c0400000050: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
  0x100c0400000060: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
  0x100c0400000070: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
  0x100c0400000080: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
  0x100c0400000090: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
=>0x100c04000000a0: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa[fd]fa
  0x100c04000000b0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
  0x100c04000000c0: fa fa fd fa fa fa fd fa fa fa fd fa fa fa 04 fa
  0x100c04000000d0: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa
  0x100c04000000e0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x100c04000000f0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==81170==ABORTING

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Alexander Egorenkov
11e78cada5 zdump: catch attempts to seek past end of file in zg_seek()
Make zg_seek() more robust.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Alexander Egorenkov
0a7df9e030 zdump: improve error handling in pt_load_add()
Verify the given ELF header before adding any memory chunks otherwise
a memory chunk might be added even if the given ELF header is invalid.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Vineeth Vijayan
7dd03eaeec zdev: Add build option to update initial RAM-disk by default
Some Linux distributions always include a copy of all persistent device
configuration data when updating the initial RAM-disk. This makes
chzdev's persistent device configuration changes ineffective because
device configuration directives applied in the RAM-disk take precedence
over those stored in the root filesystem.

This patch introduces a new build-time switch which allows distributions
to specify that whenever there is a persistent device configuration
change, the RAM-disk is updated automatically.

This feature can be enabled by adding 'ZDEV_ALWAYS_UPDATE_INITRD=1' as
a zdev build option. Where, by default ZDEV_ALWAYS_UPDATE_INITRD is 0.

Co-developed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Ingo Franzki
663262c962 zkey: Prevent sporadic error during key verification pattern generation
After a master key change, it can happen that the AF_ALG setkey
operation returns EINVAL, although the key is valid. This is a
temporary situation and the operation will succeed, once the firmware
has completed some internal processing related with the master key
change. Delay 1 second and retry up to 10 times.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-01-25 13:19:33 +01:00
Nikita Dubrovskii
bf9482709f fdasd: Use increased retry count for dasd_reread_partition_table
If fdasd is used right after dasdfmt, it may fail with the following
error due to udev still processing events for the device:

```
fdasd error:  IOCTL error: Error while rereading partition table.
```

Call dasd_reread_partition_table() with an increased retry value to
circumvent this issue.

Closes: https://github.com/ibm-s390-tools/s390-tools/pull/103
Signed-off-by: Nikita Dubrovskii <nikita@linux.ibm.com>
[hoeppner@linux.ibm.com: Reword commit message]
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Dan Horák
cdf0b5d66f hsci: fix help text
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/102
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Vance Morris
4aafd6962a netboot: Bump busybox version in pxelinux.0 build
`stime` was removed in glibc-2.31.
Busybox fixes this in https://git.busybox.net/busybox/patch/?id=d3539be8f27b8cbfdfee460fe08299158f08bcd9

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/100
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/101
Signed-off-by: Vance Morris <vmorris@us.ibm.com>
Reviewed-by: Viktor Mihajlovski mihajlov@de.ibm.com
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
863e1c3fa4 zkey: Remove warning about sector size support with crypttab
Current distributions should now all support the sector size option
in crypttab entries for plain mode dm-crypt volumes.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Juergen Christ <jchrist@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
7c47ea8e09 zkey: Add support to store LUKS2 dummy passphrase in key repository
Extend zkey to allow to store a (dummy) LUKS2 passphrase together with a
secure key, for use with LUKS2 volumes. That way, when the repository is
backed up, or archived, also the passphrases of the associated LUKS2
volumes are backed up, or archived, and thus can not be forgotten.
This passphrase is then used in generated commands to format and open
the LUKS2 volumes.

Because of the use of secure keys to encrypt the volumes, the LUKS2
passphrase is of no or less relevance for security. It is therefore OK to
store the passphrase in clear text in the key repository, and also use
them in /etc/crypttab. Therefore, the passphrase could actually be a
trivial passphrase, or a dummy passphrase.

Note: Such a dummy passphrase is NOT considered a secret that needs to
be protected. If for a certain usage the passphrase is of relevance for
security, then the zkey dummy passphrase option must not be used to store
the passphrase.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Juergen Christ <jchrist@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Alexander Egorenkov
c239d99379 genprotimg: do not fail on inline warnings caused by glib
gcc's -Werror switch also enables -Werror=inline which leads to a compilation
failure due to inline warnings caused by GLIB macros. To fix it, disable
the conversion of inline warnings into errors.

In file included from buildroot/qemu-s390x/host/bin/../s390x-buildroot-linux-gnu/sysroot/usr/lib/glib-2.0/include/glibconfig.h:9,
                 from buildroot/qemu-s390x/host/bin/../s390x-buildroot-linux-gnu/sysroot/usr/include/glib-2.0/glib/gtypes.h:32,
                 from buildroot/qemu-s390x/host/bin/../s390x-buildroot-linux-gnu/sysroot/usr/include/glib-2.0/glib/galloca.h:32,
                 from buildroot/qemu-s390x/host/bin/../s390x-buildroot-linux-gnu/sysroot/usr/include/glib-2.0/glib.h:30,
                 from pv/pv_hdr.c:10:
buildroot/qemu-s390x/build/s390-tools-2.15.1/genprotimg/src/utils/buffer.h: In function ‘pv_hdr_new’:
buildroot/qemu-s390x/host/bin/../s390x-buildroot-linux-gnu/sysroot/usr/include/glib-2.0/glib/gmacros.h:1028:49: error: inlining failed in call to ‘glib_autoptr_clear_Buffer’: call is unlikely and code size would grow [-Werror=inline]
 1028 | #define _GLIB_AUTOPTR_CLEAR_FUNC_NAME(TypeName) glib_autoptr_clear_##TypeName
      |                                                 ^~~~~~~~~~~~~~~~~~~

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Alexander Egorenkov
6c6e3a2b0e zipl/boot: fix potential heap overflow in stage2
Current heap size in stage2 is three pages long [0x6000-0x9000] but
get_zeroed_page() assumes it is one page more which might lead to
a heap overflow which will corrupt data located at 0x9000 (stage3
parameters). Calculate the heap size of a stage at run-time
by using the symbols provided by linker.

Furthermore, validate the given address in free_page() to stop illegal
memory accesses.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Alexander Egorenkov
2dca5d193f zipl/boot: fix memory use after free in stage2
Prevent access to freed memory still pointed to by entry.
entry still points into load_page that has been released with free_page.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
75675ec627 libekmfweb: Make install directory for shared libraries configurable
If LIBDIR is not passed to the make invocation, install shared libraries
to USRLIB64DIR (/usr/lib64/), even though LIBDIR defaults to /lib/. If
LIBDIR is overridden for the make invocation, install shared libraries to
whatever is specified as LIBDIR.

Closes: https://github.com/ibm-s390-tools/s390-tools/issues/98

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
18bf2cce06 zkey/zkey-ekmfweb: Install KMS plugins into configurable location
Install KMS plugins into a configurable location. The default KMS plugin
location is '/usr/lib64/zkey/', but one can set ZKEYKMSPLUGINDIR on the make
invocation to change the plugin location, e.g. to '/usr/libexec/zkey/'.

Closes: https://github.com/ibm-s390-tools/s390-tools/issues/98

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
8781dd3e7b zkey-ekmfweb: Fix selection of key properties to set or remove
When some of the key properties are skipped due to null_values_only
being true or false, then the resulting EKMF tag list might be built
incorrectly.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Ingo Franzki
6380e77f28 zkey-ekmfweb: Allow NULL as property value to remove a property
To remove a KMS property function kms_set_key_properties() can be
called with the property value set to NULL. Do not assert for non-NULL
property values.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Marc Hartmayer
733b86c02a genprotimg: remove -Winline cflag
`-Winline` can cause problems with the cleanup functions defined by
glib. Therefore let's remove the cflag for now.

DEBUG: /usr/include/glib-2.0/glib/gmacros.h:1031:43: error: inlining failed in call to 'glib_autoptr_cleanup_STACK_OF_X509_CRL.isra.0': call is unlikely and \
code size would grow [-Werror=inline]
DEBUG:  1031 | #define _GLIB_AUTOPTR_FUNC_NAME(TypeName) glib_autoptr_cleanup_##TypeName

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Marc Hartmayer
7827a791c9 genprotimg: add missing return
This should be no problem (if OpenSSL works correctly), because
`crls_download_cb` is only called out of the verification context of
OpenSSL. It's used to look up a CRL and therefore
X509_STORE_CTX_get_current_cert should always return a certificate
since X509_STORE_CTX_get_current_cert returns NULL only if an error
has occurred during the verification (see
https://www.openssl.org/docs/man1.1.0/man3/X509_STORE_CTX_get_current_cert.html).

Fixes: 074de1e14e ("genprotimg: add host-key document verification support")
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-12-15 11:10:50 +01:00
Marc Hartmayer
074de1e14e genprotimg: add host-key document verification support
Add host-key document verification support to genprotimg. This ensures
that a host-key document is genuine and provided by IBM. For this the
user must provide the IBM Z signing key, the intermediate CA
certificate (signed by the root CA used) so a chain of trust starting
from the host-key document and ending in the root CA can be
established.

By default, genprotimg tries to download all revocation lists needed
by looking up in the corresponding certificate on how CRL information
can be obtained (see https://tools.ietf.org/html/rfc5280#section-4.2.1.13
for details).

Acked-by: Patrick Steuer <patrick.steuer@de.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-18 11:28:35 +01:00
Ingo Franzki
07d181e29b zkey: Fix APQN property names
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-18 11:28:35 +01:00
Marc Hartmayer
895a88b2f8 genprotimg: require argument for 'ramdisk' and 'parmfile' options
A argument is required for the optional options 'ramdisk' and
'parmfile'.

Fixes: 65b9fc442c ("genprotimg: introduce new tool for the creation of PV images")
Reviewed-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-18 11:28:35 +01:00
Ingo Franzki
f01f8b240c zkey-ekmfweb: Fix typo in message
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-18 11:28:35 +01:00
Jan Höppner
be2bc610b7 netboot: Add version information to scripts
Add the -v short option for version information to the mk-s390image and
mk-pxelinux-ramfs. Adjust the Makefile accordingly to set the correct
s390-tools version during installation.

Acked-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-18 11:28:35 +01:00
Marc Hartmayer
c48d45ba92 common.mak: use '--' for rm calls to distinguish between options and files
Use '--' for rm calls to distinguish between options and files. This
fixes, for example, the following error:

make[1]: Entering directory '/root/git/s390-tools/genprotimg/src'
rm -f *.gcda *.gcno *.gcov
rm: invalid option -- '.'
Try 'rm ./-.gcno' to remove the file '-.gcno'.
Try 'rm --help' for more information.
make[1]: *** [../../common.mak:369: clean_gcov] Error 1

Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-18 11:28:35 +01:00
Thomas Richter
886476a207 cpumf/chcpumf.c: Print proper error message on non-root invocation
chcpumf must be executed as root. A non-root user sees this error
message:

[tester@t35lp46 ~]$ chcpumf -m 1000
Error: /sys/module/kernel/parameters/cpum_sfb_size: Permission denied
[tester@t35lp46 ~]$

Enhance the error message and be clear about the root cause:
[tester@t35lp46 ~]$ chcpumf-new  -m 1000
Error: Must run as root
[tester@t35lp46 ~]$

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-18 11:28:35 +01:00
Thomas Richter
86685f001d cpumf/lscpumf.c: Check for help and version options first
Check command line arguments for help text and version
string first, before doing any action. This ensures this
information is always printed, even when invoked as non-root
user.

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/97
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-18 11:28:35 +01:00
Jan Höppner
d619b492e9 lsdasd: Add FC Endpoint Security information
Provide the status of the FC Endpoint Security information via the long
output of lsdasd for online Base and Alias devices.

New Output:

$ lsdasd -l c600
0.0.c600/dasdd/9412
  status:                               n/f
  type:                                 ECKD
  blksz:                                512
  size:
  blocks:
  extent_size:                          1113
  logical_capacity:                     1113
  space_allocated:                      1113
  use_diag:                             0
  readonly:                             0
  eer_enabled:                          0
  erplog:                               0
  hpf:                                  1
  uid:                                  IBM.750000000KMV11.c600.00
  fc_security:                          Encryption
  paths_installed:                      38 39 3a 3b
  paths_in_use:                         38 39 3a 3b
  paths_non_preferred:
  paths_invalid_cabling:
  paths_cuir_quiesced:
  paths_invalid_hpf_characteristics:
  paths_error_threshold_exceeded:

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-12 10:50:48 +01:00
Jan Höppner
79e4798061 zdev: Add FC Endpoint Security information for DASD devices
Provide information for the DASD device attribute 'fc_security'.
The help output for this attribute can be queried like this:

chzdev dasd --help-attribute

The lszdev tool can be used to display the current state of the FC
Endpoint Security information:

lszdev dasd -a -c TYPE,ID,ATTR:fc_security,ATTRPATH:fc_security

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-12 10:50:48 +01:00
Ingo Franzki
cf2311f1f1 zcryptstats: Fix handling of partial results with many domains
When many domains per card are available, then the results of the SCDMD
CHSC call may not fit into the output area, and a partial result is
returned. The further results must be retrieved with another CHSC call.

Fix the code to pass the correct next-domain to the subsequent CHSC call
of a partial response. Otherwise the same set of domains 1 to n are
retrieved again, resulting in an infinite loop, because this will always
produce a partial result.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-12 08:06:11 +01:00
Colin Walters
7e832da790 systemd/cpi.service: Add RemainAfterExit=yes
Noticed this while looking at the unit file for a different
RHEL CoreOS issue.

See https://github.com/ostreedev/ostree/pull/1697
and https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=750683

Omitting this can cause the service to run multiple times if
something else ends up depending on it, which I'm guessing
we don't want.

Closes: https://github.com/ibm-s390-tools/s390-tools/pull/72
Signed-off-by: Colin Walters <walters@verbum.org>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-11 14:25:46 +01:00
Dan Horák
3b402a0630 lscpumf: add z15 Model T02
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/87
Signed-off-by: Dan Horák <dan@danny.cz>
Reviewed-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-11 14:25:46 +01:00
Dan Horák
3437c9bb90 netboot/mk-s390image: add simple man page
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/94
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-11 14:25:46 +01:00
Philipp Kern
8898650266 scripts/zipl-switch-to-blscfg.1: Fix some typos
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/90
Signed-off-by: Philipp Kern <pkern@google.com>
Acked-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-11 14:25:46 +01:00
Prashanth Sundararaman
3ae2100d5e systemd/cpi.service: Add sysinit.target dependency to make sure /var is created
Noticed on RHEL CoreOS that the CPI service failed to start with:

"Cannot access lock file: /var/lock/cpictl.lock"

This was a timing issue where /var was not created yet and the symlink
to /run/lock was not present. Add sysinit.target to fix this.
This fix has been tested with RHEL CoreOS.

Closes: https://github.com/ibm-s390-tools/s390-tools/pull/82
Signed-off-by: Prashanth Sundararaman <psundara@redhat.com>
Suggested-by: Colin Walters <walters@verbum.org>
Reviewed-by: Dan Horák <dan@danny.cz>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-11 14:25:46 +01:00
Alexander Egorenkov
93e4249fd3 zkey/ekmfweb: fix linking of libekmfweb
Use -L compiler's parameter instead of the environment variable
LIBRARY_PATH.

Fixes the following problem on buildroot:

buildroot/qemu-s390x/host/bin/s390x-linux-gcc -shared -Wl,--version-script=zkey-ekmfweb.map -Wl,-z,defs,-Bsymbolic -Wl,-soname,zkey-ekmfweb.so.1 zkey-ekmfweb.o properties.o pkey.o cca.o ep11.o utils.o ../..//libutil/libutil.a -lekmfweb -ldl -lcrypto -o zkey-ekmfweb.so
buildroot/qemu-s390x/host/bin/s390x-linux-gcc -I ../../include -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I ../include -std=gnu99 -Wno-unused-parameter -Wno-missing-field-initializers -DS390_TOOLS_RELEASE=2.15.1-build-20201105 -DS390_TOOLS_LIBDIR=/lib/s390-tools -DS390_TOOLS_DATADIR=/usr/share/s390-tools -DS390_TOOLS_SYSCONFDIR=/etc -DS390_TOOLS_BINDIR=/sbin -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os   -D_GNU_SOURCE -c udev_ccwgroup.c -o udev_ccwgroup.o
buildroot/qemu-s390x/host/bin/s390x-linux-gcc -I ../../include -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I ../include -std=gnu99 -Wno-unused-parameter -Wno-missing-field-initializers -DS390_TOOLS_RELEASE=2.15.1-build-20201105 -DS390_TOOLS_LIBDIR=/lib/s390-tools -DS390_TOOLS_DATADIR=/usr/share/s390-tools -DS390_TOOLS_SYSCONFDIR=/etc -DS390_TOOLS_BINDIR=/sbin -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os   -D_GNU_SOURCE -c iscsi.c -o iscsi.o
buildroot/qemu-s390x/host/bin/s390x-linux-gcc -I ../../include -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I ../include -std=gnu99 -Wno-unused-parameter -Wno-missing-field-initializers -DS390_TOOLS_RELEASE=2.15.1-build-20201105 -DS390_TOOLS_LIBDIR=/lib/s390-tools -DS390_TOOLS_DATADIR=/usr/share/s390-tools -DS390_TOOLS_SYSCONFDIR=/etc -DS390_TOOLS_BINDIR=/sbin -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os   -D_GNU_SOURCE -c dasd.c -o dasd.o
buildroot/qemu-s390x/host/opt/ext-toolchain/bin/../lib/gcc/s390x-buildroot-linux-gnu/9.3.0/../../../../s390x-buildroot-linux-gnu/bin/ld: cannot find -lekmfweb
collect2: error: ld returned 1 exit status
make[4]: *** [Makefile:36: zkey-ekmfweb.so] Error 1
make[3]: *** [Makefile:128: ekmfweb] Error 2
buildroot/qemu-s390x/host/bin/s390x-linux-gcc -I ../../include -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I ../include -std=gnu99 -Wno-unused-parameter -Wno-missing-field-initializers -DS390_TOOLS_RELEASE=2.15.1-build-20201105 -DS390_TOOLS_LIBDIR=/lib/s390-tools -DS390_TOOLS_DATADIR=/usr/share/s390-tools -DS390_TOOLS_SYSCONFDIR=/etc -DS390_TOOLS_BINDIR=/sbin -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os   -D_GNU_SOURCE -c zfcp.c -o zfcp.o
make[2]: *** [Makefile:43: zkey] Error 2
make[2]: *** Waiting for unfinished jobs....

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-11 14:25:46 +01:00
Jan Höppner
8ec4705239 libutil: Compare proc entries to vfstype
Modern systems have systemd manage system mount points like sysfs which
specify 'sysfs' as a keyword for the device as there is no device
associated with this special filesystem. However, any arbitrary string
could be specified here and the determination of the sysfs mount point
would fail in such a case.
To make sure that the mount point of the sysfs is still found when
mounted with a device keyword specified other than 'sysfs', check for
the filesystem type instead, which is more specific.

Fixes: https://github.com/ibm-s390-tools/s390-tools/issues/91
Suggested-by: Mark Post <mpost@suse.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-09 12:24:32 +01:00
Jan Höppner
cad450fdf9 dasdfmt: Make error function less error-prone
Add a proper definition to the dasdfmt header file of the error()
function that lets the compiler check the format string against the
provided parameters.

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-09 12:24:32 +01:00
Dan Horák
3a1cda59ce libekmfweb: fix permissions for ekmfweb.h
Closes: https://github.com/ibm-s390-tools/s390-tools/pull/96
Signed-off-by: Dan Horák <dan@danny.cz>
Acked-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-09 10:39:46 +01:00
Wenjia Zhang
0566a492ae hsci: Add new tool to control HiperSockets Converged Interfaces
hsci is used to control and show HSCI (HiperSockets Converged Interfaces)
settings. A HiperSockets interface and an external network interface are
converged to an HSCI interface.

Signed-off-by: Alexandra Winter <wintera@linux.ibm.com>
Signed-off-by: Wenjia Zhang <wenjia@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-09 10:16:22 +01:00
Marc Hartmayer
bc7359d2a3 iucvterm: abort if one of the recursive targets is failing
Abort processing as soon as one of the recursive targets is failing.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-06 16:18:21 +01:00
Marc Hartmayer
db6f272607 genprotimg: fix two memory leaks
==1005844== HEAP SUMMARY:
==1005844==     in use at exit: 18,907 bytes in 14 blocks
==1005844==   total heap usage: 82 allocs, 68 frees, 32,529 bytes allocated
==1005844==
==1005844== 136 (104 direct, 32 indirect) bytes in 1 blocks are definitely lost in loss record 12 of 14
==1005844==    at 0x483885A: calloc (vg_replace_malloc.c:760)
==1005844==    by 0x48C950D: g_malloc0 (gmem.c:132)
==1005844==    by 0x100EC41: pv_args_new (pv_args.c:364)
==1005844==    by 0x100587F: main (genprotimg.c:122)
==1005844==
==1005844== LEAK SUMMARY:
==1005844==    definitely lost: 104 bytes in 1 blocks
==1005844==    indirectly lost: 32 bytes in 1 blocks
==1005844==      possibly lost: 0 bytes in 0 blocks
==1005844==    still reachable: 18,771 bytes in 12 blocks
==1005844==         suppressed: 0 bytes in 0 blocks
==1005844== Reachable blocks (those to which a pointer was found) are not shown.
==1005844== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==1005844==
==1005844== For lists of detected and suppressed errors, rerun with: -s
==1005844== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-06 16:18:21 +01:00
Marc Hartmayer
6db7fbe018 genprotimg: abort if one of the recursive targets is failing
Abort compilation as soon as one of the recursive targets is failing.

Fixes: 65b9fc442c ("genprotimg: introduce new tool for the creation of PV images")
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-06 16:18:21 +01:00
Sven Schnelle
2f154fa49d cmsfs-fuse: fix pointer block level calculation
Adding one to the pointer per block value results in a wrong
calculation of pointer block levels. When writing a file that
would result in about 454MB size, the code would calculate that
it needs a two level pointer directory but correct would be a three
level pointer directory. This causes an invalid filesystem state:
besides missing all the records of one top level pointer directory
entry, it would also record a higher record number in the FST than
what is present in the pointer blocks.

Note that this bug only hits when the file is about 454MB and the write
is stopped (means the file is closed) - if file writing continues the
problem doesn't happen because at some point in time cmsfs-fuse would
switch to three levels of pointer blocks anyways as the file grows.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-06 16:18:21 +01:00
Jan Höppner
148d3f9b64 dasdfmt: Fix segfault when an incorrect option is specified
When specifying an incorrect program option, dasdfmt segfaults as the
format string for the corresponding error message has no parameter.
Add the missing parameter to fix this.

Fixes: 732b3dddab ("dasdfmt: Replace ERRMSG_EXIT macro with an error handling function")
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-03 09:05:29 +01:00
Brian C. Lane
702dc96264 netboot: Clear kernel cmdline data before writing new parmfile
If this isn't cleared first it can end up with an unexpected cmdline if
it doesn't completely overwrite the default data.

Closes: https://github.com/ibm-s390-tools/s390-tools/pull/95
Reviewed-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-03 09:05:29 +01:00
Jan Höppner
313092b202 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2020-11-03 09:05:29 +01:00
78 changed files with 3906 additions and 333 deletions

View File

@@ -9,12 +9,14 @@ List of all individuals having contributed content to s390-tools
- Arnd Bergmann
- Axel Wirbser
- Benjamin Block
- Brian C. Lane
- Carsten Otte
- Christian Borntraeger
- Christian Ehrhardt
- Christof Schmitt
- Claudio Imbrenda
- Clemens von Mann
- Colin Walters
- Dan Horak
- Despina Papadopoulou
- Dimitri John Ledkov
@@ -75,11 +77,13 @@ List of all individuals having contributed content to s390-tools
- Michael Mueller
- Mijo Safradin
- Mikhail Zaslonko
- Nikita Dubrovskii
- Niklas Schnelle
- Peter Oberparleiter
- Peter Tiedemann
- Philipp Kern
- Philipp Rudo
- Prashanth Sundararaman
- Rafael Fonseca
- Raimund Schroeder
- Ralph Wuerthner
@@ -109,7 +113,10 @@ List of all individuals having contributed content to s390-tools
- Tuan Hoang
- Ursula Braun
- Utz Bacher
- Vance Morris
- Vasily Gorbik
- Viktor Mihajlovski
- Vineeth Vijayan
- Volker Sameske
- Wenjia Zhang
- Wolfgang Taphorn

View File

@@ -1,5 +1,36 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.16.0 (2021-02-19)__
For Linux kernel version: 5.10 / 5.11
Add new tool:
- hsci: New tool to manage HSCI (HiperSockets Converged Interfaces)
Changes of existing tools:
- genprotimg: Add host-key document verification support
- genprotimg: boot: Make boot loader -march=z900 compatible
- libekmfweb: Make install directory for shared libraries configurable
- lsdasd: Add FC Endpoint Security information
- make: Add address sanitizer support
- netboot: Add version information to scripts
- netboot: Bump busybox version in pxelinux.0 build
- zdev: Add FC Endpoint Security information for DASD devices
- zdev: Add build option to update initial RAM-disk by default
- zkey-ekmfweb: Avoid sequence number clash when generating keys
- zkey/zkey-ekmfweb: Install KMS plugins into configurable location
- zkey: Add support to store LUKS2 dummy passphrase in key repository
Bug Fixes:
- dasdfmt: Fix segfault when an incorrect option is specified
- genprotimg: Fix several build issues
- genprotimg: Require argument for 'ramdisk' and 'parmfile' options
- zcryptstats: Fix handling of partial results with many domains
- zfcpdbf: Deal with crash 7.2.9 change in caller name formatting
- zipl/boot: Fix memory use after free in stage2
- zipl/boot: Fix potential heap overflow in stage2
- zipl: Fix reading 4k disk's geometry
* __v2.15.1 (2020-10-28)__
For Linux kernel version: 5.9

View File

@@ -72,7 +72,7 @@ In the examples below we use this fictive identity:
### Setup GitHub and local git
1. Create a fork of this repository by clicking the `Fork` button on the top
right of the [s390-tools](https://github.com/ibm-s390-tools/s390-tools)
right of the [s390-tools](https://github.com/ibm-s390-linux/s390-tools)
main page
2. Clone your forked repository to your local development system
@@ -84,7 +84,7 @@ In the examples below we use this fictive identity:
s390-tools repository on GitHub
```
$ cd s390-tools
~/s390-tools $ git remote add upstream https://github.com/ibm-s390-tools/s390-tools.git
~/s390-tools $ git remote add upstream https://github.com/ibm-s390-linux/s390-tools.git
```
4. Verify your remotes
@@ -92,8 +92,8 @@ In the examples below we use this fictive identity:
~/s390-tools $ git remote -v
origin https://github.com/random-developer/s390-tools.git (fetch)
origin https://github.com/random-developer/s390-tools.git (push)
upstream https://github.com/ibm-s390-tools/s390-tools.git (fetch)
upstream https://github.com/ibm-s390-tools/s390-tools.git (push)
upstream https://github.com/ibm-s390-linux/s390-tools.git (fetch)
upstream https://github.com/ibm-s390-linux/s390-tools.git (push)
```
You now have two remotes: The "origin" remote points to your fork
and the "upstream" remote to the official s390-tools repository.

View File

@@ -9,7 +9,7 @@ TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
genprotimg lsstp
genprotimg lsstp hsci
SUB_DIRS = $(LIB_DIRS) $(TOOL_DIRS)

View File

@@ -249,6 +249,9 @@ Package contents
Management Foundation - Web Edition, and is used to manage keys in an
enterprise.
* hsci:
Manage HiperSockets Converged Interfaces (HSCI).
For more information refer to the following publications:
* "Device Drivers, Features, and Commands" chapter "Useful Linux commands"
@@ -277,14 +280,15 @@ build options:
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb |
| glib2 | `HAVE_GLIB2` | genprotimg |
| libcurl | `HAVE_LIBCURL` | libekmfweb |
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb |
This table lists additional build or install options:
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|----------------|:----------------:|:-------------------------------:|
| dracut | `HAVE_DRACUT` | zdev |
| initramfs-tools| `HAVE_INITRAMFS` | zdev |
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|------------------|:----------------------------:|:--------------:|
| dracut | `HAVE_DRACUT` | zdev |
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
The s390-tools build process uses "pkg-config" if available and hard-coded
compiler and linker options otherwise.
@@ -375,6 +379,17 @@ the different tools are provided:
Distributors with different boot or RAM-disk mechanisms should provide
a custom zdev-root-update helper script.
- `ZDEV_ALWAYS_UPDATE_INITRD=1` upon modification of any persistent device
configuration, chzdev updates the initial RAM-disk by default, without any
additional user interaction.
For some distributions, all the configuration attributes must be copied to
the initial RAM-disk. Because the device configuration directives applied
in the initial RAM-disk takes precedence over those stored in the root file-
system. This copying is done usually by explicitly invoking a command. This
build option makes it user-friendly and does this copying without any manual
intervention.
Some functions of zdev require that the following programs are available:
- modprobe (kmod)

View File

@@ -299,7 +299,7 @@ static unsigned long dec_to_hex(unsigned long long num)
{
unsigned long res;
asm volatile("cvb %0,%1" : "=d" (res) : "m" (num));
asm volatile("cvb %0,%1" : "=d" (res) : "Q" (num));
return res & 0xffffffff;
}
@@ -307,7 +307,7 @@ static unsigned int hex_to_dec(unsigned int num)
{
unsigned long long res;
asm volatile("cvd %1,%0" : "=m" (res) : "d" (num));
asm volatile("cvd %1,%0" : "=Q" (res) : "d" (num));
return res & 0xffffffff;
}
@@ -2050,7 +2050,7 @@ static int update_dir_levels(int blocks)
if (blocks < 2)
return 0;
while (blocks / (PTRS_PER_BLOCK + 1)) {
while (blocks / PTRS_PER_BLOCK) {
levels++;
blocks /= PTRS_PER_BLOCK;
}
@@ -3103,7 +3103,7 @@ static void update_levels(struct file *f)
return;
}
while (blocks / (per_block + 1)) {
while (blocks / per_block) {
levels++;
blocks /= per_block;
}

View File

@@ -5,8 +5,8 @@ COMMON_INCLUDED = true
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION = 2
RELEASE = 15
PATCHLEVEL = 1
RELEASE = 16
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
export S390_TOOLS_RELEASE
@@ -106,6 +106,11 @@ endif
DEFAULT_CPPFLAGS = -D_GNU_SOURCE
DEFAULT_LDFLAGS = -rdynamic
ifeq ("${ASAN}","1")
DEFAULT_CFLAGS += -fsanitize=address -fno-omit-frame-pointer
DEFAULT_LDFLAGS += -fsanitize=address
endif
#
# Check for build dependency
#
@@ -174,12 +179,20 @@ ZFCPDUMP_DIR = $(TOOLS_LIBDIR)/zfcpdump
# for SYSTEMDSYSTEMUNITDIR (e.g. /lib/systemd/system)
SYSTEMDSYSTEMUNITDIR =
USRINCLUDEDIR = $(INSTALLDIR)/usr/include
ZKEYKMSPLUGINDIR = $(USRLIB64DIR)/zkey
ifeq ($(LIBDIR),$(INSTALLDIR)/lib)
SOINSTALLDIR = $(USRLIB64DIR)
else
SOINSTALLDIR = $(LIBDIR)
endif
INSTDIRS = $(USRSBINDIR) $(USRBINDIR) $(BINDIR) $(LIBDIR) $(MANDIR) \
$(SYSCONFDIR) $(SYSCONFDIR)/sysconfig \
$(TOOLS_LIBDIR) $(TOOLS_DATADIR) \
$(ZFCPDUMP_DIR) $(SYSTEMDSYSTEMUNITDIR) \
$(USRLIB64DIR) $(USRINCLUDEDIR)
$(USRLIB64DIR) $(USRINCLUDEDIR) $(ZKEYKMSPLUGINDIR) \
$(SOINSTALLDIR)
OWNER = $(shell id -un)
GROUP = $(shell id -gn)
export INSTALLDIR BINDIR LIBDIR USRLIB64DIR MANDIR OWNER GROUP
@@ -264,6 +277,7 @@ help:
@echo ' G=1 Build with gcov to collect code coverage data'
@echo ' V=1 Generate verbose build output'
@echo ' W=1 Build with higher warning level'
@echo ' ASAN=1 Build with address sanitizer'
@echo ''
@echo 'EXAMPLES'
@echo ' # make clean all D=1 W=1 -j'
@@ -366,9 +380,9 @@ install: install_echo install_dirs
clean_echo:
$(call echocmd," CLEAN ")
clean_gcov:
rm -f *.gcda *.gcno *.gcov
rm -f -- *.gcda *.gcno *.gcov
clean_dep:
rm -f .*.o.d
rm -f -- .*.o.d
clean: clean_echo clean_gcov clean_dep
endif

View File

@@ -91,13 +91,18 @@ static int read_sfb(unsigned long *min, unsigned long *max)
int rc = EXIT_SUCCESS;
FILE *fp;
if (geteuid()) {
fprintf(stderr, "Error: Must run as root\n");
return EXIT_FAILURE;
}
fp = fopen(PERF_SFB_SIZE, "r");
if (fp == NULL) {
linux_error(PERF_SFB_SIZE);
return EXIT_FAILURE;
}
if (fscanf(fp, "%ld,%ld", &cur_min_sdb, &cur_max_sdb) != 2) {
fprintf(stderr, "Error: Can not parse file " PERF_SFB_SIZE);
fprintf(stderr, "Error: Can not parse file " PERF_SFB_SIZE
"\n");
rc = EXIT_FAILURE;
} else {
if (*min == 0)

View File

@@ -2572,6 +2572,7 @@ static const char *machine_name(void)
case 3906: return "IBM z14";
case 3907: return "IBM z14 ZR1";
case 8561: return "IBM z15";
case 8562: return "IBM z15 Model T02";
}
return "Unknown hardware model";
}
@@ -3094,11 +3095,11 @@ int main(int argc, char **argv)
util_prg_init(&prg);
util_opt_init(opt_vec, NULL);
ret = read_info();
if (ret == EXIT_FAILURE)
return ret;
ret = parse_args(argc, argv);
if (read_info() == EXIT_FAILURE)
return EXIT_FAILURE;
switch ((ret = parse_args(argc, argv))) {
switch (ret) {
case ACTION_CNT:
case ACTION_CNTALL:
all = ret == ACTION_CNTALL;
@@ -3114,6 +3115,7 @@ int main(int argc, char **argv)
case ACTION_NONE:
case ACTION_INFO:
show_info(&cpumf, ret == ACTION_INFO);
ret = EXIT_SUCCESS;
break;
}
return ret;

View File

@@ -1637,7 +1637,7 @@ int main(int argc, char *argv[])
/* End of options string - start of devices list */
break;
default:
error("Try '%s --help' for more information.");
error("Try '%s --help' for more information.", prog_name);
}
if (rc == -1)

View File

@@ -41,6 +41,10 @@ static const char mode_str[3][10] = {
"Full", "Quick", "Expand"
};
/* Report error, free memory, and exit */
static void error(const char *format, ...)
__attribute__((__noreturn__, __format__(__printf__, 1, 2)));
#define DASD_PARTN_BITS 2
#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)

View File

@@ -1232,7 +1232,7 @@ static void fdasd_reread_partition_table(fdasd_anchor_t *anc)
if (!anc->silent)
printf("rereading partition table...\n");
if (dasd_reread_partition_table(options.device, 1) != 0) {
if (dasd_reread_partition_table(options.device, 5) != 0) {
fdasd_error(anc, unable_to_ioctl, "Error while rereading "
"partition table.\nPlease reboot!");
}

View File

@@ -21,7 +21,7 @@ clean: clean-recursive
$(RECURSIVE_TARGETS):
@target=`echo $@ |sed s/-recursive//`; \
for d in $(SUBDIRS); do \
$(MAKE) -C $$d $$target; \
$(MAKE) -C $$d $$target || exit 1; \
done
.PHONY: all install clean $(RECURSIVE_TARGETS)

View File

@@ -1,5 +1,5 @@
/*
* Entry code for stage 3a boot loader
* Entry code for stage 3a and stage 3b boot loader
*
* Copyright IBM Corp. 2020
*
@@ -24,6 +24,8 @@ _start:
sam64
/* Initialize stack */
lgfi %r15, STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
basr %r13, 0
.Lbase: llgf %r15, .Lstack - .Lbase(%r13)
brasl %r14, initialize
.Lstack: .long STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
.previous

View File

@@ -21,6 +21,8 @@ _init:
* kernel command line and the address and size of the
* ramdisk. Simply ignore this by starting at 0x11000.
*/
lgfi %r1, STAGE3A_ENTRY
basr %r13, 0
.Lbase: llgf %r1, .Lstage3a_entry - .Lbase(%r13)
br %r1
.Lstage3a_entry: .long STAGE3A_ENTRY
.previous

View File

@@ -31,12 +31,12 @@ stage3b_reloc_start:
sigp %r1, %r0, SIGP_SET_ARCHITECTURE
sam64
.copy_stage3b:
/* Location of stage3b in memory */
larl %r8, stage3b_start
/* Destination for stage3b */
lgfi %r9, STAGE3B_LOAD_ADDRESS
basr %r13, 0
.Lbase: llgf %r9, .Lstage3b_load_address - .Lbase(%r13)
/* Size of stage3b */
lghi %r11, stage3b_end - stage3b_start
@@ -45,8 +45,10 @@ stage3b_reloc_start:
MEMCPY %r9, %r8, %r11
/* Branch to STAGE3B_ENTRY */
lgfi %r9, STAGE3B_ENTRY
llgf %r9, .Lstage3b_entry - .Lbase(%r13)
br %r9
.Lstage3b_load_address: .long STAGE3B_LOAD_ADDRESS
.Lstage3b_entry: .long STAGE3B_ENTRY
stage3b_start:
.incbin "stage3b.bin"
stage3b_end:

View File

@@ -2,7 +2,7 @@
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH GENPROTIMG 8 "March 2020" "s390-tools"
.TH GENPROTIMG 8 "November 2020" "s390-tools"
.SH NAME
genprotimg \- Create a protected virtualization image
@@ -10,6 +10,7 @@ genprotimg \- Create a protected virtualization image
.SY
.B genprotimg
\fB\-k\fR \fIHOST_KEY_DOCUMENT\fR...
\fB\-C\fR \fICERTIFICATE\fR...
\fB\-i\fR \fIVMLINUZ\fR
[\fB\-r\fR \fIRAMDISK\fR]
[\fB\-p\fR \fIPARMFILE\fR]
@@ -21,15 +22,19 @@ genprotimg \- Create a protected virtualization image
.PP
Use \fBgenprotimg\fR to generate a single bootable image file with
encrypted and integrity-protected parts. The command requires a kernel
image, a host-key document, and an output file name. Optionally,
specify an initial RAM filesystem, and a file containing the kernel
parameters. Should special circumstances require it, you can
image, a host-key document, certificates for the host-key document
verification, and an output file name. Optionally, specify an initial
RAM filesystem, and a file containing the kernel parameters. If the
command should be run offline, use the \fB\-\-offline\fR option and
specify the certificate revocation lists (CRLs) by using the
\fB\-\-crl\fR option. Should special circumstances require it, you can
optionally specify your own keys for the encryption by using the
experimental options. In the resulting image file, a plain text boot
loader, the encrypted components for kernel, initial RAM disk, kernel
parameters, and the encrypted and integrity-protected header are
concatenated. The header contains metadata necessary for running the
guest in protected mode.
experimental options. For all certificates, CRLs, and host-key
documents, both the PEM and DER input formats are supported. In the
resulting image file, a plain text boot loader, the encrypted
components for kernel, initial RAM disk, kernel parameters, and the
encrypted and integrity-protected header are concatenated. The header
contains metadata necessary for running the guest in protected mode.
.PP
Use this image file as a kernel image for zipl or for a direct kernel
boot using QEMU.
@@ -53,6 +58,12 @@ Specifies a host-key document. At least one is required. Specify this
option multiple times to enable the image to run on more than one
host.
.TP
\fB\-C\fR, \fB\-\-cert\fR=\fI\,FILE\/\fR
Specifies the certificate that is used to establish a chain of trust
for the verification of the host-key documents. Specify this option
twice to specify the IBM Z signing key and the intermediate CA
certificate (signed by the root CA). Required.
.TP
\fB\-o\fR, \fB\-\-output\fR=\fI\,OUTPUT_FILE\/\fR
Specifies the output file. Required.
.TP
@@ -65,6 +76,20 @@ Specifies the RAM disk image. Optional.
\fB\-p\fR, \fB\-\-parmfile\fR=\fI\,PARMFILE\/\fR
Specifies the kernel command line stored in \fI\,PARMFILE\/\fR. Optional.
.TP
\fB\-\-crl\fR=\fI\,FILE\/\fR
Specifies the revocation list that is used to check whether a
certificate of the chain of trust is revoked. Specify this option
multiple times to use multiple CRLs. Optional.
.TP
\fB\-\-offline\fR
Specifies offline mode, in which no attempt is made to download
CRLs. Optional.
.TP
\fB\-\-root\-ca\fR=\fI\,FILE\/\fR
Specifies the root CA certificate for the verification. If omitted,
the DigiCert root CA certificate installed on the system is used. Use
this only if you trust the specified certificate. Optional.
.TP
\fB\-\-no-verify\fR
Do not require the host-key documents to be valid. For testing
purposes, do not use for a production image. Optional.
@@ -77,11 +102,13 @@ Prints version information, then exits.
Generate a protected virtualization image in
\fI\,/boot/vmlinuz.pv\/\fR, using the kernel file \fI\,vmlinuz\/\fR,
the initrd in \fI\,initramfs\/\fR, the kernel parameters contained in
\fI\,parmfile\/\fR, and the host-key document in \fI\,host_key.crt\/\fR:
\fI\,parmfile\/\fR, the intermediate CA in \fI\,DigiCertCA.crt\/\fR,
the IBM Z signing key in \fI\,ibm-z-host-key-signing.crt\/\fR, and the
host-key document in \fI\,host_key.crt\/\fR:
.PP
.Vb 1
.EX
\& genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-o \fI\,/boot/vmlinuz.pv\/\fR
\& genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt \-o \fI\,/boot/vmlinuz.pv\/\fR
.EE
.Ve
.PP

View File

@@ -15,24 +15,24 @@ INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
WARNINGS := -Wall -Wextra -Wshadow \
-Wcast-align -Wwrite-strings -Wmissing-prototypes \
-Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline \
-Wmissing-declarations -Wredundant-decls -Wnested-externs \
-Wno-long-long -Wuninitialized -Wconversion -Wstrict-prototypes \
-Wpointer-arith -Werror \
-Wpointer-arith -Werror -Wno-error=inline \
$(NULL)
$(bin_PROGRAM)_SRCS := $(bin_PROGRAM).c pv/pv_stage3.c pv/pv_image.c \
pv/pv_comp.c pv/pv_hdr.c pv/pv_ipib.c utils/crypto.c utils/file_utils.c \
pv/pv_args.c utils/buffer.c pv/pv_comps.c pv/pv_error.c \
pv/pv_opt_item.c \
pv/pv_opt_item.c utils/curl.c \
$(NULL)
$(bin_PROGRAM)_OBJS := $($(bin_PROGRAM)_SRCS:.c=.o)
ALL_CFLAGS += -std=gnu11 -DPKGDATADIR=$(PKGDATADIR) \
$(GLIB2_CFLAGS) $(LIBCRYPTO_CFLAGS) \
$(GLIB2_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBCURL_CFLAGS) \
$(WARNINGS) \
$(NULL)
ALL_CPPFLAGS += $(INCLUDE_PARMS)
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS)
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS) $(LIBCURL_LIBS)
ifneq ($(shell sh -c 'command -v pkg-config'),)
@@ -40,21 +40,27 @@ GLIB2_CFLAGS := $(shell pkg-config --silence-errors --cflags glib-2.0)
GLIB2_LIBS := $(shell pkg-config --silence-errors --libs glib-2.0)
LIBCRYPTO_CFLAGS := $(shell pkg-config --silence-errors --cflags libcrypto)
LIBCRYPTO_LIBS := $(shell pkg-config --silence-errors --libs libcrypto)
LIBCURL_CFLAGS := $(shell pkg-config --silence-errors --cflags libcurl)
LIBCURL_LIBS := $(shell pkg-config --silence-errors --libs libcurl)
else
GLIB2_CFLAGS := -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include
GLIB2_LIBS := -lglib-2.0
LIBCRYPTO_CFLAGS :=
LIBCRYPTO_LIBS := -lcrypto
LIBCURL_CFLAGS :=
LIBCURL_LIBS := -lcurl
endif
BUILD_TARGETS := skip-$(bin_PROGRAM)
INSTALL_TARGETS := skip-$(bin_PROGRAM)
ifneq (${HAVE_OPENSSL},0)
ifneq (${HAVE_GLIB2},0)
ifneq (${HAVE_LIBCURL},0)
BUILD_TARGETS := $(bin_PROGRAM)
INSTALL_TARGETS := install-$(bin_PROGRAM)
endif
endif
endif
all: $(BUILD_TARGETS)
@@ -98,4 +104,9 @@ $($(bin_PROGRAM)_OBJS): .check-dep-$(bin_PROGRAM)
"openssl-devel / libssl-dev version >= 1.1.0", \
"HAVE_OPENSSL=0", \
"-I.")
$(call check_dep, \
"$(bin_PROGRAM)", \
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0")
touch $@

View File

@@ -18,6 +18,8 @@
#include "common.h"
#include "pv/pv_args.h"
#include "pv/pv_image.h"
#include "utils/crypto.h"
#include "utils/curl.h"
enum {
LOG_LEVEL_CRITICAL = 0,
@@ -117,6 +119,8 @@ static void remove_signal_handler(const gint *signals, const gsize signals_n)
signal(signals[i], SIG_DFL);
}
static void __attribute__((constructor)) __init(void);
static void __attribute__((destructor)) __cleanup(void);
gint main(gint argc, gchar *argv[])
{
g_autoptr(PvArgs) args = pv_args_new();
@@ -177,5 +181,20 @@ error:
rmdir_recursive(tmp_dir, NULL);
remove_signal_handler(signals, G_N_ELEMENTS(signals));
g_free(tmp_dir);
g_clear_pointer(&img, pv_img_free);
g_clear_pointer(&args, pv_args_free);
exit(ret);
}
static void __init(void)
{
pv_crypto_init();
if (curl_init() != 0)
g_abort();
}
static void __cleanup(void)
{
curl_cleanup();
pv_crypto_cleanup();
}

View File

@@ -14,6 +14,24 @@
#include "lib/zt_common.h"
/* IBM signing key subject */
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME "Poughkeepsie"
#define PV_IBM_Z_SUBJECT_ORGANIZATIONONAL_UNIT_NAME_SUFFIX "Key Signing Service"
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_STATE "New York"
#define PV_IMB_Z_SUBJECT_ENTRY_COUNT 6
/* Minimum security level for the keys/certificates used to establish a chain of
* trust (see https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_auth_level.html
* for details).
*/
#define PV_CERTS_SECURITY_LEVEL 2
/* SKID for DigiCert Assured ID Root CA */
#define DIGICERT_ASSURED_ID_ROOT_CA_SKID "45EBA2AFF492CB82312D518BA7A7219DF36DC80F"
union ecdh_pub_key {
struct {
uint8_t x[80];

View File

@@ -18,7 +18,9 @@
static gchar summary[] =
"Use genprotimg to create a protected virtualization kernel image file,\n"
"which can be loaded using zipl or QEMU.";
"which can be loaded using zipl or QEMU. For all certificates, revocation\n"
"lists, and host-key documents, both the PEM and DER input formats are\n"
"supported.";
static gint pv_arg_compare(gconstpointer arg_1, gconstpointer arg_2)
{
@@ -97,9 +99,14 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
return -1;
}
if (!args->no_verify) {
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
_("Use the option '--no-verify' as the verification support is not available yet."));
if (!args->no_verify &&
(!args->untrusted_cert_paths ||
g_strv_length(args->untrusted_cert_paths) == 0)) {
g_set_error(
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
_("Either specify the IBM Z signing key and (DigiCert) intermediate CA certificate\n"
"by using the '--cert' option, or use the '--no-verify' flag to disable the\n"
"host-key document verification completely (at your own risk)."));
return -1;
}
@@ -141,6 +148,8 @@ static gboolean cb_set_string_option(const gchar *option, const gchar *value,
{
gchar **args_option = NULL;
if (g_str_equal(option, "--root-ca"))
args_option = &args->root_ca_path;
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
args_option = &args->output_path;
if (g_str_equal(option, "--x-comp-key"))
@@ -211,6 +220,18 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
_("FILE specifies a host-key document. At least\n" INDENT
"one is required."),
.arg_description = _("FILE") },
{ .long_name = "cert",
.short_name = 'C',
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_FILENAME_ARRAY,
.arg_data = &args->untrusted_cert_paths,
.description = _(
"FILE contains a certificate that is used to\n" INDENT
"establish a chain of trust for the verification\n" INDENT
"of the host-key documents. The IBM Z signing\n" INDENT
"key and intermediate CA certificate (signed\n" INDENT
"by the root CA) are required."),
.arg_description = _("FILE") },
{ .long_name = "output",
.short_name = 'o',
.flags = G_OPTION_FLAG_FILENAME,
@@ -227,7 +248,7 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
.arg_description = _("IMAGE") },
{ .long_name = "ramdisk",
.short_name = 'r',
.flags = G_OPTION_FLAG_OPTIONAL_ARG | G_OPTION_FLAG_FILENAME,
.flags = G_OPTION_FLAG_FILENAME,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_add_component,
.description = _("Use RAMDISK as the initial RAM disk\n" INDENT
@@ -235,12 +256,37 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
.arg_description = _("RAMDISK") },
{ .long_name = "parmfile",
.short_name = 'p',
.flags = G_OPTION_FLAG_OPTIONAL_ARG | G_OPTION_FLAG_FILENAME,
.flags = G_OPTION_FLAG_FILENAME,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_add_component,
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
"(optional)."),
.arg_description = _("PARMFILE") },
{ .long_name = "crl",
.short_name = 0,
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_FILENAME_ARRAY,
.arg_data = &args->crl_paths,
.description = _(
"FILE contains a certificate revocation list\n" INDENT
"(optional)."),
.arg_description = _("FILE") },
{ .long_name = "offline",
.short_name = 0,
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_NONE,
.arg_data = &args->offline,
.description = _("Don't download CRLs (optional)."),
.arg_description = NULL },
{ .long_name = "root-ca",
.short_name = 0,
.flags = G_OPTION_FLAG_FILENAME,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_set_string_option,
.description = _(
"Set FILE as the trusted root CA and don't use the\n" INDENT
"root CAs that are installed on the system (optional)."),
.arg_description = _("FILE") },
{ .long_name = "no-verify",
.short_name = 0,
.flags = G_OPTION_FLAG_NONE,
@@ -378,6 +424,9 @@ void pv_args_free(PvArgs *args)
g_free(args->cust_root_key_path);
g_free(args->cust_comm_key_path);
g_free(args->gcm_iv_path);
g_free(args->root_ca_path);
g_strfreev(args->crl_paths);
g_strfreev(args->untrusted_cert_paths);
g_strfreev(args->host_keys);
g_free(args->xts_key_path);
g_slist_free_full(args->comps, (GDestroyNotify)pv_arg_free);

View File

@@ -25,6 +25,7 @@ void pv_arg_free(PvArg *arg);
typedef struct {
gint log_level;
gint no_verify;
gboolean offline;
gchar *pcf;
gchar *scf;
gchar *psw_addr; /* PSW address which will be used for the start of
@@ -34,6 +35,11 @@ typedef struct {
gchar *cust_comm_key_path;
gchar *gcm_iv_path;
gchar **host_keys;
gchar *root_ca_path; /* Trusted root CA used for the verification of the
* chain of trust (if specified).
*/
gchar **untrusted_cert_paths;
gchar **crl_paths;
gchar *xts_key_path;
GSList *comps;
gchar *output_path;

View File

@@ -28,6 +28,8 @@ typedef enum {
PV_ERROR_IPIB_SIZE,
PV_ERROR_PV_HDR_SIZE,
PV_ERROR_INTERNAL,
PV_ERROR_CURL_INIT_FAILED,
PV_ERROR_DOWNLOAD_FAILED,
} PvErrors;
typedef enum {
@@ -57,6 +59,31 @@ typedef enum {
PV_CRYPTO_ERROR_RANDOMIZATION,
PV_CRYPTO_ERROR_INVALID_PARM,
PV_CRYPTO_ERROR_INVALID_KEY_SIZE,
PV_CRYPTO_ERROR_INVALID_VALIDITY_PERIOD,
PV_CRYPTO_ERROR_EXPIRED,
PV_CRYPTO_ERROR_NOT_VALID_YET,
PV_CRYPTO_ERROR_LOAD_CRL,
PV_CRYPTO_ERROR_NO_PUBLIC_KEY,
PV_CRYPTO_ERROR_INVALID_SIGNATURE_ALGORITHM,
PV_CRYPTO_ERROR_SIGNATURE_ALGORITHM_MISMATCH,
PV_CRYPTO_ERROR_INVALID_URI,
PV_CRYPTO_ERROR_CRL_DOWNLOAD_FAILED,
PV_CRYPTO_ERROR_CERT_SIGNATURE_INVALID,
PV_CRYPTO_ERROR_CRL_SIGNATURE_INVALID,
PV_CRYPTO_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
PV_CRYPTO_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
PV_CRYPTO_ERROR_MALFORMED_CERTIFICATE,
PV_CRYPTO_ERROR_NO_CRL,
PV_CRYPTO_ERROR_LOAD_ROOT_CA,
PV_CRYPTO_ERROR_LOAD_DEFAULT_CA,
PV_CRYPTO_ERROR_MALFORMED_ROOT_CA,
PV_CRYPTO_ERROR_WRONG_CA_USED,
PV_CRYPTO_ERROR_SKID_AKID_MISMATCH,
PV_CRYPTO_ERROR_NO_ISSUER_IBM_Z_FOUND,
PV_CRYPTO_ERROR_FAILED_DOWNLOAD_CRL,
PV_CRYPTO_ERROR_NO_CRLDP,
PV_CRYPTO_ERROR_CERT_REVOKED,
} PvCryptoErrors;
#endif

View File

@@ -10,6 +10,7 @@
#include <errno.h>
#include <glib.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -138,22 +139,18 @@ static EVP_PKEY *pv_img_get_cust_pub_priv_key(gint nid, GError **err)
return generate_ec_key(nid, err);
}
static HostKeyList *pv_img_get_host_keys(gchar **host_cert_paths,
X509_STORE *store, gint nid,
static HostKeyList *pv_img_get_host_keys(GSList *host_keys_with_path, gint nid,
GError **err)
{
g_autoslist(EVP_PKEY) ret = NULL;
g_assert(host_cert_paths);
for (gchar **iterator = host_cert_paths; iterator != NULL && *iterator != NULL;
iterator++) {
for (GSList *iterator = host_keys_with_path; iterator;
iterator = iterator->next) {
x509_with_path *cert_with_path = iterator->data;
g_autoptr(EVP_PKEY) host_key = NULL;
const gchar *path = *iterator;
X509 *cert = cert_with_path->cert;
g_assert(path);
host_key = read_ec_pubkey_cert(store, nid, path, err);
host_key = read_ec_pubkey_cert(cert, nid, err);
if (!host_key)
return NULL;
@@ -253,10 +250,172 @@ static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
return 0;
}
static gint pv_img_hostkey_verify(GSList *host_key_certs,
const gchar *root_ca_path,
const gchar *const *crl_paths,
const gchar *const *untrusted_cert_paths,
gboolean offline, GError **err)
{
g_autoslist(x509_with_path) untrusted_certs_with_path = NULL;
g_autoptr(STACK_OF_X509) ibm_signing_certs = NULL;
g_autoptr(STACK_OF_X509) untrusted_certs = NULL;
g_autoslist(x509_pair) ibm_z_pairs = NULL;
g_autoptr(X509_STORE) trusted = NULL;
gint ibm_signing_certs_count;
/* Load trusted root CAs of the system if and only if @root_ca_path is
* NULL, otherwise use the root CA specified by @root_ca_path.
*/
trusted = store_setup(root_ca_path, crl_paths, err);
if (!trusted)
goto error;
if (!offline) {
g_autoptr(STACK_OF_X509_CRL) downloaded_ibm_signing_crls = NULL;
/* Set up the download routine for the lookup of CRLs. */
store_setup_crl_download(trusted);
/* Try to download the CRLs of the IBM Z signing certificates
* specified in the host-key documents. Ignore download errors
* as it's still possible that a CRL is specified via command
* line.
*/
downloaded_ibm_signing_crls = try_load_crls_by_certs(host_key_certs);
/* Add the downloaded CRLs to the store so they can be used for
* the verification later.
*/
for (int i = 0; i < sk_X509_CRL_num(downloaded_ibm_signing_crls); i++) {
X509_CRL *crl = sk_X509_CRL_value(downloaded_ibm_signing_crls, i);
if (X509_STORE_add_crl(trusted, crl) != 1) {
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("failed to load CRL"));
goto error;
}
}
}
/* Load all untrusted certificates (e.g. IBM Z signing key and
* DigiCert intermediate CA) that are required to establish a chain of
* trust starting from the host-key document up to the root CA (if not
* otherwise specified that's the DigiCert Assured ID Root CA).
*/
untrusted_certs_with_path = load_certificates(untrusted_cert_paths, err);
if (!untrusted_certs_with_path)
goto error;
/* Convert to STACK_OF(X509) */
untrusted_certs = get_x509_stack(untrusted_certs_with_path);
/* Find all IBM Z signing keys and remove them from the chain as we
* have to verify that they're valid. The last step of the chain of
* trust verification must be done manually, as the IBM Z signing keys
* are not marked as (intermediate) CA and therefore the standard
* `X509_verify_cert` function of OpenSSL cannot be used to verify the
* actual host-key documents.
*/
ibm_signing_certs = delete_ibm_signing_certs(untrusted_certs);
ibm_signing_certs_count = sk_X509_num(ibm_signing_certs);
if (ibm_signing_certs_count < 1) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
_("please specify at least one IBM Z signing key"));
goto error;
} else if (ibm_signing_certs_count > 1) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
_("please specify only one IBM Z signing key"));
goto error;
}
if (store_set_verify_param(trusted, err) < 0)
goto error;
/* Verify that the IBM Z signing keys are trustable.
* For this we must check:
*
* 1. Can a chain of trust be established ending in a root CA
* 2. Is the correct root CA ued? It has either to be the
* 'DigiCert Assured ID Root CA' or the root CA specified via
* command line.
*/
for (gint i = 0; i < sk_X509_num(ibm_signing_certs); ++i) {
X509 *ibm_signing_cert = sk_X509_value(ibm_signing_certs, i);
g_autoptr(STACK_OF_X509_CRL) ibm_signing_crls = NULL;
g_autoptr(X509_STORE_CTX) ctx = NULL;
x509_pair *pair = NULL;
g_assert(ibm_signing_cert);
/* Create the verification context and set the trusted
* and chain parameters.
*/
ctx = create_store_ctx(trusted, untrusted_certs, err);
if (!ctx)
goto error;
/* Verify the IBM Z signing key */
if (verify_cert(ibm_signing_cert, ctx, err) < 0)
goto error;
/* Verify the build chain of trust chain. If the user passes a
* trusted root CA on the command line then the check for the
* Subject Key Identifier (SKID) is skipped, otherwise let's
* check if the SKID meets our expectation.
*/
if (!root_ca_path &&
check_chain_parameters(X509_STORE_CTX_get0_chain(ctx),
get_digicert_assured_id_root_ca_skid(),
err) < 0) {
goto error;
}
ibm_signing_crls = store_ctx_find_valid_crls(ctx, ibm_signing_cert, err);
if (!ibm_signing_crls) {
g_prefix_error(err, _("IBM Z signing key: "));
goto error;
}
/* Increment reference counter of @ibm_signing_cert as the
* certificate will now also be owned by @ibm_z_pairs.
*/
if (X509_up_ref(ibm_signing_cert) != 1)
g_abort();
pair = x509_pair_new(&ibm_signing_cert, &ibm_signing_crls);
ibm_z_pairs = g_slist_append(ibm_z_pairs, pair);
g_assert(!ibm_signing_cert);
g_assert(!ibm_signing_crls);
}
/* Verify host-key documents by using the IBM Z signing
* certificates and the corresponding certificate revocation
* lists.
*/
for (GSList *iterator = host_key_certs; iterator; iterator = iterator->next) {
x509_with_path *host_key_with_path = iterator->data;
const gchar *host_key_path = host_key_with_path->path;
X509 *host_key = host_key_with_path->cert;
gint flags = X509_V_FLAG_CRL_CHECK;
if (verify_host_key(host_key, ibm_z_pairs, flags,
PV_CERTS_SECURITY_LEVEL, err) < 0) {
g_prefix_error(err, "'%s': ", host_key_path);
goto error;
}
}
return 0;
error:
g_prefix_error(err, _("Failed to verify host-key document: "));
return -1;
}
/* read in the keys or auto-generate them */
static gint pv_img_set_keys(PvImage *img, const PvArgs *args, GError **err)
{
g_autoptr(X509_STORE) store = NULL;
g_autoslist(x509_with_path) host_key_certs = NULL;
g_assert(img->xts_cipher);
g_assert(img->cust_comm_cipher);
@@ -285,8 +444,25 @@ static gint pv_img_set_keys(PvImage *img, const PvArgs *args, GError **err)
if (!img->cust_pub_priv_key)
return -1;
/* Load all host-key documents specified on the command line */
host_key_certs = load_certificates((const gchar **)args->host_keys,
err);
if (!host_key_certs)
return -1;
if (!args->no_verify &&
pv_img_hostkey_verify(host_key_certs, args->root_ca_path,
(const gchar * const *)args->crl_paths,
(const gchar * const *)args->untrusted_cert_paths,
args->offline, err) < 0) {
return -1;
}
/* Loads the public keys stored in the host-key documents and verify
* that the correct elliptic curve is used.
*/
img->host_pub_keys =
pv_img_get_host_keys(args->host_keys, store, img->nid, err);
pv_img_get_host_keys(host_key_certs, img->nid, err);
if (!img->host_pub_keys)
return -1;
@@ -406,6 +582,9 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
if (args->no_verify)
g_warning(_("host-key document verification is disabled. Your workload is not secured."));
if (args->root_ca_path)
g_warning(_("A different root CA than the default DigiCert root CA is selected. Ensure that this root CA is trusted."));
ret->comps = pv_img_comps_new(EVP_sha512(), EVP_sha512(), EVP_sha512(), err);
if (!ret->comps)
return NULL;

File diff suppressed because it is too large Load Diff

View File

@@ -11,14 +11,18 @@
#define PV_UTILS_CRYPTO_H
#include <glib.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/evp.h>
#include <openssl/ossl_typ.h>
#include <openssl/rand.h>
#include <openssl/safestack.h>
#include <openssl/sha.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <stdint.h>
#include "common.h"
@@ -33,6 +37,9 @@
#define AES_256_XTS_TWEAK_SIZE 16
#define AES_256_XTS_KEY_SIZE 64
#define CRL_DOWNLOAD_TIMEOUT_MS 3000
#define CRL_DOWNLOAD_MAX_SIZE (1024 * 1024) /* in bytes */
enum PvCryptoMode {
PV_ENCRYPT,
PV_DECRYPT,
@@ -40,7 +47,34 @@ enum PvCryptoMode {
typedef GSList HostKeyList;
/* play nice with g_autoptr */
typedef STACK_OF(DIST_POINT) STACK_OF_DIST_POINT;
typedef STACK_OF(X509) STACK_OF_X509;
typedef STACK_OF(X509_CRL) STACK_OF_X509_CRL;
void STACK_OF_DIST_POINT_free(STACK_OF_DIST_POINT *stack);
void STACK_OF_X509_free(STACK_OF_X509 *stack);
void STACK_OF_X509_CRL_free(STACK_OF_X509_CRL *stack);
typedef struct {
X509 *cert;
const gchar *path;
} x509_with_path;
x509_with_path *x509_with_path_new(X509 *cert, const gchar *path);
void x509_with_path_free(x509_with_path *cert);
typedef struct {
X509 *cert;
STACK_OF_X509_CRL *crls;
} x509_pair;
x509_pair *x509_pair_new(X509 **cert, STACK_OF_X509_CRL **crls);
void x509_pair_free(x509_pair *pair);
/* Register auto cleanup functions */
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_INTEGER, ASN1_INTEGER_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_OCTET_STRING, ASN1_OCTET_STRING_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIGNUM, BN_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIO, BIO_free_all)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BN_CTX, BN_CTX_free)
@@ -51,10 +85,18 @@ WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_MD_CTX, EVP_MD_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY, EVP_PKEY_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY_CTX, EVP_PKEY_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_DIST_POINT, STACK_OF_DIST_POINT_free);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509, STACK_OF_X509_free);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509_CRL, STACK_OF_X509_CRL_free);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509, X509_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_CRL, X509_CRL_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_LOOKUP, X509_LOOKUP_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_NAME, X509_NAME_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(x509_pair, x509_pair_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE, X509_STORE_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE_CTX, X509_STORE_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(x509_with_path, x509_with_path_free)
union cmp_index {
struct {
@@ -79,8 +121,37 @@ struct cipher_parms {
const Buffer *iv_or_tweak;
};
EVP_PKEY *read_ec_pubkey_cert(X509_STORE *store, gint nid, const gchar *path,
GError **err);
int check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
gint verify_flags, GError **err);
void pv_crypto_init(void);
void pv_crypto_cleanup(void);
const ASN1_OCTET_STRING *get_digicert_assured_id_root_ca_skid(void);
gint verify_host_key(X509 *host_key, GSList *issuer_pairs,
gint verify_flags, int level, GError **err);
X509 *load_cert_from_file(const char *path, GError **err);
X509_CRL *load_crl_from_file(const gchar *path, GError **err);
GSList *load_certificates(const gchar *const *cert_paths, GError **err);
STACK_OF_X509 *get_x509_stack(const GSList *x509_with_path_list);
X509_STORE *store_setup(const gchar *root_ca_path,
const gchar * const *crl_paths,
GError **err);
int store_set_verify_param(X509_STORE *store, GError **err);
X509_CRL *load_crl_by_cert(X509 *cert, GError **err);
STACK_OF_X509_CRL *try_load_crls_by_certs(GSList *certs_with_path);
gint check_chain_parameters(const STACK_OF_X509 *chain,
const ASN1_OCTET_STRING *skid, GError **err);
X509_NAME *c2b_name(const X509_NAME *name);
STACK_OF_X509 *delete_ibm_signing_certs(STACK_OF_X509 *certs);
STACK_OF_X509_CRL *store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert,
GError **err);
X509_STORE_CTX *create_store_ctx(X509_STORE *trusted, STACK_OF_X509 *chain,
GError **err);
gint verify_cert(X509 *cert, X509_STORE_CTX *ctx, GError **err);
X509_CRL *get_first_valid_crl(X509_STORE_CTX *ctx, X509 *cert, GError **err);
void store_setup_crl_download(X509_STORE *st);
EVP_PKEY *read_ec_pubkey_cert(X509 *cert, gint nid, GError **err);
Buffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err);
Buffer *generate_aes_key(guint size, GError **err);
Buffer *generate_aes_iv(guint size, GError **err);

121
genprotimg/src/utils/curl.c Normal file
View File

@@ -0,0 +1,121 @@
/*
* Libcurl utils
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <glib.h>
#include <glib/gtypes.h>
#include <curl/curl.h>
#include "lib/zt_common.h"
#include "pv/pv_error.h"
#include "curl.h"
struct UserData {
GByteArray *buffer;
guint max_size;
};
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
g_assert(userdata);
struct UserData *data = (struct UserData *)userdata;
GByteArray *buffer = data->buffer;
guint64 actual_size;
size_t err;
g_assert(buffer);
if (!g_uint64_checked_mul(&actual_size, size, nmemb))
g_abort();
/* Signal an error condition by returning a amount that differs
* from the amount passed to the callback. This results in a
* CURLE_WRITE_ERROR.
*/
err = actual_size + 1;
if (actual_size > G_MAXUINT)
return err;
data->buffer = g_byte_array_append(buffer, (guchar *)ptr, (guint)actual_size);
if (data->buffer->len > data->max_size)
return err;
return actual_size;
}
gint curl_init(void)
{
if (curl_global_init(CURL_GLOBAL_ALL) != 0)
return -1;
return 0;
}
void curl_cleanup(void)
{
curl_global_cleanup();
}
GByteArray *curl_download(const gchar *url, long timeout_ms, guint max_size,
GError **err)
{
g_autoptr(GByteArray) ret = NULL;
g_autoptr(CURL) handle = NULL;
g_autofree gchar *agent = NULL;
struct UserData userdata;
CURLcode rc;
/* set up curl session */
handle = curl_easy_init();
if (!handle)
g_abort();
/* follow redirection */
rc = curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1l);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_TIMEOUT_MS, timeout_ms);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1l);
if (rc != CURLE_OK)
goto curl_err;
agent = g_strdup_printf("%s/%s", tool_name, RELEASE_STRING);
rc = curl_easy_setopt(handle, CURLOPT_USERAGENT, agent);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
if (rc != CURLE_OK)
goto curl_err;
ret = g_byte_array_new();
userdata.buffer = ret;
userdata.max_size = max_size;
rc = curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&userdata);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_URL, url);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_perform(handle);
if (rc != CURLE_OK) {
g_set_error(err, PV_ERROR, PV_ERROR_DOWNLOAD_FAILED,
_("download failed: %s"), curl_easy_strerror(rc));
return NULL;
}
return g_steal_pointer(&ret);
curl_err:
g_set_error(err, PV_ERROR,
PV_ERROR_CURL_INIT_FAILED,
_("cURL initialization failed: %s"),
curl_easy_strerror(rc));
return NULL;
}

View File

@@ -0,0 +1,25 @@
/*
* Libcurl utils
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_UTILS_LIBCURL_H
#define PV_UTILS_LIBCURL_H
#include <glib.h>
#include <curl/curl.h>
#include "common.h"
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURL, curl_easy_cleanup)
GByteArray *curl_download(const gchar *url, long timeout_ms, guint max_size,
GError **err);
gint curl_init(void);
void curl_cleanup(void);
#endif /* PV_UTILS_LIBCURL_H */

16
hsci/Makefile Normal file
View File

@@ -0,0 +1,16 @@
include ../common.mak
all:
install: hsci
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
< hsci >$(DESTDIR)$(BINDIR)/hsci; \
chown $(OWNER).$(GROUP) $(DESTDIR)$(BINDIR)/hsci; \
chmod 755 $(DESTDIR)$(BINDIR)/hsci; \
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 hsci.8 \
$(DESTDIR)$(MANDIR)/man8
clean:
.PHONY: all install clean

436
hsci/hsci Executable file
View File

@@ -0,0 +1,436 @@
#!/bin/bash
#
# hsci - Tool to manage HiperSockets Converged Interfaces (HSCI)
#
# Copyright IBM Corp. 2020
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
hsdev=""
ndev=""
hsci=""
hsdev_mac=""
hsif_pnetid=""
netif_pnetid=""
hsci_pnetid=""
function usage {
cat <<-EOD
Usage: hsci COMMAND [OPTION]
This tool is designed to control and show HSCI (HiperSockets Converged
Interfaces) settings. A HiperSockets interface and an external network
interface are converged into an HSCI interface.
COMMANDS
add HIPERSOCKETS_DEV NET_DEV Adds an HSCI interface
del HSCI_NAME Deletes an HSCI interface
show Lists the configured HSCI interfaces
OPTIONS:
-v, --version Prints the version number of the hsci tool and exits
-h, --help Displays the help information for the command
EOD
}
function prereqs_check {
if ! [ -x "$(command -v ip)" ]; then
echo "Error: No iproute2 installed on this system" >&2
return 1
fi
}
function check_pnetids {
# get PNETID of the HS
local hsif_pnetids=""
local netif_pnetids=""
if [ -e /sys/class/net/$hsdev/device/util_string ]; then
hsif_pnetids="$(cat /sys/class/net/$hsdev/device/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
else
if [ -e /sys/class/net/$hsdev/device/chpid ]; then
chpid="$(cat /sys/class/net/$hsdev/device/chpid | tr [:upper:] [:lower:])"
hsif_pnetids="$(cat /sys/devices/css0/chp0.$chpid/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
fi
fi
if [ "$hsif_pnetids" != "" ]; then
port_hsif="$(cat /sys/class/net/$hsdev/dev_port)"
(( idx=16*$port_hsif+1 ))
(( end=$idx+15 ))
hsif_pnetid="$(echo "$hsif_pnetids" | cut -c $idx-$end | tr -d ' ')"
fi
# get PNETID of the NET_DEV
if [ -e /sys/class/net/$ndev/device/util_string ]; then
netif_pnetids="$(cat /sys/class/net/$ndev/device/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
else
if [ -e /sys/class/net/$ndev/device/chpid ]; then
chpid="$(cat /sys/class/net/$ndev/device/chpid | tr [:upper:] [:lower:])"
netif_pnetids="$(cat /sys/devices/css0/chp0.$chpid/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
fi
fi
if [ "$netif_pnetids" != "" ]; then
port_netif="$(cat /sys/class/net/$ndev/dev_port)"
(( idx=16*$port_netif+1 ))
(( end=$idx+15 ))
netif_pnetid="$(echo "$netif_pnetids" | cut -c $idx-$end | tr -d ' ')"
fi
#Check PNETIDs
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" != "$hsif_pnetid" ]; then
echo "Error: $hsdev and $ndev have different PNETIDs! They are $hsif_pnetid and $netif_pnetid respectively" >&2
return 1
fi
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" == "$hsif_pnetid" ]; then
hsci_pnetid=$hsif_pnetid
fi
}
function verify_precon {
echo "Verifying net dev $ndev and HiperSockets dev $hsdev"
if [ ! -e /sys/class/net/$hsdev ]; then
echo "Error: $hsdev does not exist" >&2
return 1
fi
if [ "$(cat /sys/class/net/$hsdev/device/card_type)" != "HiperSockets" ]; then
echo "Error: $hsdev is not a HiperSockets device" >&2
return 1
fi
if [ "$(cat /sys/class/net/$hsdev/device/layer2)" != "1" ]; then
echo "Error: $hsdev is not in layer 2 mode" >&2
return 1
fi
if [ ! -e /sys/class/net/$hsdev/device/vnicc/bridge_invisible ]; then
echo "Error: Missing vnic-characteristics support" >&2
return 1
fi
if [ "$(cat /sys/class/net/$hsdev/device/vnicc/bridge_invisible)" == "n/a" ]; then
echo "Error: $hsdev does not support vnicc" >&2
return 1
fi
if [ $(ip link show $hsdev | grep UP | wc -l) -eq 0 ]; then
echo "Error: $hsdev is not in state UP" >&2
return 1
fi
if [ $(bridge -d link show dev $hsdev self | grep learning_sync | wc -l) -eq 0 ]; then
echo "Error: $hsdev does not support attribute learning_sync" >&2
return 1
fi
if [ $(ip link show $hsdev | grep master | wc -l) -ne 0 ]; then
echo "Error: $hsdev is already a bridge port" >&2
return 1
fi
#Pre-verify net_dev
if [ ! -e /sys/class/net/$ndev ]; then
echo "Error: $ndev does not exist" >&2
return 1
fi
if [ "$(cat /sys/class/net/$ndev/device/card_type)" == "HiperSockets" ]; then
echo "Error: $ndev is also a HiperSockets device" >&2
return 1
fi
if [ $(ip link show $ndev | grep UP | wc -l) -eq 0 ]; then
echo "Error: $ndev is not in state UP" >&2
return 1
fi
if [ $(ip link show $ndev | grep master | wc -l) -ne 0 ]; then
echo "Error: $ndev is already a bridge port" >&2
return 1
fi
#Check PNETIDs
check_pnetids
if [ $? -ne 0 ]; then
return 1
fi
return 0
}
function clean_up {
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
echo 0 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible >/dev/null 2>&1
bridge fdb del $hsdev_mac dev $ndev >/dev/null 2>&1
ip link del $hsci >/dev/null 2>&1
}
##############################################################################
## add a new HSCI interface
##############################################################################
function add_hsci {
if [ $# != 2 ]; then
echo "hsci: Invalid parameters" >&2
echo "Use 'hsci --help' for more information" >&2
return 1
fi
hsdev=$1
ndev=$2
#### Verify preconditions
verify_precon
if [ $? -ne 0 ]; then
return 1
fi
hsci_postfix="$(readlink /sys/class/net/$hsdev/device/cdev0 | tail -c5)"
hsci=hsci$hsci_postfix
echo "Adding $hsci with a HiperSockets dev $hsdev and an external dev $ndev"
#### Create bridge
ip link add name $hsci type bridge stp_state 0 >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Could not create a bridge" >&2
return 1
fi
#### Prepare hsdev
# Set VNICC of hsdev to invisible
#(mandatory for co-existence with HS-OSA bridges!)
echo 1 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
#### Create bridge ports
ip link set dev $ndev master $hsci >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Could not set master for $ndev" >&2
clean_up
return 1
fi
ip link set dev $hsdev master $hsci >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Could not set master for $hsdev" >&2
clean_up
return 1
fi
# no forwarding between ndev and hsdev -> isolated on
# ndev is default for outgoing unknown targets -> flood on
# no need to learn external LAN targets into fdb -> learning off
bridge link set dev $ndev isolated on learning off flood on mcast_flood on >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set bridge attributes on $ndev" >&2
clean_up
return 1
fi
# no forwarding between ndev and hsdev -> isolated on
# fdb will be populated by dev-to-bridge-notification, no need to learn
# -> learning off
# only send to hsdev, if listed in fdb -> flood off
# don't send MC/BC on hsdev -> mcast_flood off
bridge link set dev $hsdev isolated on learning off flood off mcast_flood off >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set bridge attributes on $hsdev" >&2
clean_up
return 1
fi
# NOTE: Although not required, BCs will be sent out on hsdev.
# NOTE: We need to receive BCs on hsdev, as z/OS HSCI does ARP requests on HS.
hsdev_mac="$(cat /sys/class/net/$hsdev/address)"
echo "Set $hsdev MAC $hsdev_mac on $ndev and $hsci"
# set HS MAC on OSA as secondary MAC
bridge fdb add $hsdev_mac dev $ndev >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set HS MAC on OSA as secondary MAC" >&2
clean_up
return 1
fi
# set HS MAC (common MAC) on HSCI as primary MAC
ip link set address $hsdev_mac dev $hsci >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set HiperSockets MAC (common MAC) on HSCI as primary MAC" >&2
clean_up
return 1
fi
ip link set dev $hsci up >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to set $hsci up" >&2
clean_up
return 1
fi
# Turn on device for bridge notification
bridge link set dev $hsdev learning_sync on self >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to turn on device for bridge notification" >&2
clean_up
return 1
fi
echo "Successfully added HSCI interface $hsci"
return 0
}
##############################################################################
## Delete HSCI
##############################################################################
function del_hsci {
if [ $# != 1 ]; then
echo "hsci: invalid parameters" >&2
echo "Use 'hsci --help' for more information" >&2
return 1
fi
hsci=$1
if [ $(ip link show dev $hsci | wc -l) -eq 0 ]; then
echo "Error: $hsci does not exit" >&2
return 1
fi
if [ $(ip link show | grep "master $hsci" | wc -l) -eq 0 ]; then
echo "Error: $hsci is not an active HSCI interface" >&2
return 1
fi
bports="$(ip link show | grep "master $hsci" | awk '{print $2}')"
for bport in $bports; do
bport=${bport%:}
if [[ $bport == *@* ]]; then
bport=${bport%@*}
fi
if [ $(bridge -d link show dev $bport | grep "learning_sync on" | wc -l) -ne 0 ]; then
hsdev=$bport
else
ndev=$bport
fi
done
if [ "$hsdev" == "" ]; then
echo "Error: $hsci has no active HiperSockets port" >&2
return 1
fi
echo "Deleting HSCI interface $hsci with the HiperSockets $hsdev and the external $ndev"
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to turn off learning_sync on $hsdev" >&2
return 1
fi
echo 0 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
hsdev_mac="$(cat /sys/class/net/$hsdev/address)"
echo "Deleting $hsev MAC $hsdev_mac on $ndev"
bridge fdb del $hsdev_mac dev $ndev >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to delete $hsev MAC $hsdev_mac on $ndev" >&2
return 1
fi
ip link del $hsci >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Error: Failed to delete $hsci" >&2
return 1
fi
echo "Successfully deleted device $hsci"
return 0
}
##############################################################################
## Show HSCI
##############################################################################
function list_active {
hsdev=$1
local ext=""
hsci="$(ip link show dev $hsdev | awk '{for(x=1;x<NF;x++) if($x~/master/) print $(x+1)}')"
ext="$(ip link show | grep "master $hsci" | grep --invert-match $hsdev | awk '{print $2}')"
# remove trailing ':'
ndev="${ext%:}"
check_pnetids
printf '%-8s %-16s %-15s %-15s\n' "$hsci" "$hsci_pnetid" "$hsdev" "$ndev"
return 0
}
function print_header {
if [ $header -eq 0 ]; then
echo "HSCI PNET_ID HiperSockets External "
echo "------------------------------------------------------------"
fi
}
function list_one {
local hsnetdev=$1
if [ $(bridge -d link show dev $hsnetdev | grep "learning_sync on" | wc -l) -ne 0 ]; then
print_header
list_active $hsnetdev
fi
return 0
}
function show_hsci {
if [ $# != 0 ]; then
echo "hsci: invalid parameters" >&2
echo "Use 'hsci --help' for more information" >&2
return 1
fi
header=0
for hs_net_dev in $(ls -1 /sys/class/net/); do
list_one $hs_net_dev
done
return 0
}
#==============================================================================
function print_version()
{
echo "hsci utility: version %S390_TOOLS_VERSION%"
echo "Copyright IBM Corp. 2020"
}
##############################################################################
##### Main
##############################################################################
prereqs_check
args="$(getopt -u -o hv -l help,version -- $*)"
[ $? -ne 0 ] && exit 2
set -- $args
while true; do
case $1 in
-v | --version)
print_version
exit 0
;;
-h | --help)
usage
exit 0
;;
--)
;;
add) shift
add_hsci "$@"
exit $?
;;
del) shift
del_hsci "$@"
exit $?
;;
show) shift
show_hsci "$@"
exit $?
;;
*) echo "hsci: Please specify a valid command or option" >&2
echo "Use 'hsci --help' for more information" >&2
exit 1
esac
shift
done

100
hsci/hsci.8 Normal file
View File

@@ -0,0 +1,100 @@
.\" Copyright IBM Corp. 2020
.TH HSCI 8 "November 2020" "s390-tools" "Linux Programmer's Manual"
.SH NAME
.B hsci
\- control and show HSCI settings.
.SH SYNOPSIS
.B hsci add
.I HSDEV
.I NETDEV
.br
.B hsci del
.I HSCINAME
.br
.B hsci show
.br
.B hsci [\-hv]
.SH DESCRIPTION
.BI hsci
is used to control and show HSCI (HiperSockets Converged Interfaces) settings. A HiperSockets interface and an external network interface are converged into an HSCI interface.
.SH COMMANDS
.TP
.B add \fIHSDEV\fR \fINETDEV\fR
.RS .4i
.PP
Adds an HSCI interface
.PP
.I HSDEV
is the interface name of the HiperSockets device to be converged into the HSCI interface.
.PP
.I NETDEV
is the interface name of the external network device to be converged into the HSCI interface.
.RE
.TP
.B del \fIHSCINAME\fR
.RS .4i
.PP
Deletes an HSCI interface
.PP
.I HSCINAME
is the name of the HSCI interface for the HiperSockets device and the external network device.
.RE
.TP
.B show
.RS .4i
.PP
Lists the configured HSCI interfaces.
.RE
.SH OPTIONS
.TP
.BR \-v ", " \-\-version
Prints the version number of hsci and exits.
.TP
.BR \-h ", " \-\-help
Displays the help information for the command.
.SH EXIT CODES
.TP
.BR "0"
The hsci command ran successfully.
.TP
.BR "1"
An error occurred.
.SH EXAMPLE
.BR "hsci show"
.TP
.RB
Lists the configured HSCI interfaces:
.RS 1.2i
HSCI PNET_ID HiperSockets External
.br
-----------------------------------------
.br
hsci8410 NET1 enc8410 encb040
.RE
.SH SEE ALSO
.nf
ip(8), bridge(8)
.fi
.SH AUTHOR
.nf
Written by Alexandra Winter <wintera@linux.ibm.com>
Wenjia Zhang <wenjia@linux.ibm.com>
.fi

View File

@@ -21,7 +21,7 @@ clean: clean-recursive
$(RECURSIVE_TARGETS):
@target=`echo $@ |sed s/-recursive//`; \
for d in $(SUBDIRS); do \
(cd $$d && $(MAKE) $$target) \
(cd $$d && $(MAKE) $$target) || exit 1; \
done

View File

@@ -77,11 +77,11 @@ libekmfweb.so.$(VERSION): ekmfweb.o utilities.o cca.o
ln -srf libekmfweb.so.$(VERSION) libekmfweb.so
install-libekmfweb.so.$(VERSION): libekmfweb.so.$(VERSION)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T libekmfweb.so.$(VERSION) $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERSION)
ln -srf $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERM)
ln -srf $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(USRLIB64DIR)/libekmfweb.so
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T libekmfweb.so.$(VERSION) $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERSION)
ln -srf $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERM)
ln -srf $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so.$(VERSION) $(DESTDIR)$(SOINSTALLDIR)/libekmfweb.so
$(INSTALL) -d -m 770 $(DESTDIR)$(USRINCLUDEDIR)/ekmfweb
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 $(rootdir)include/ekmfweb/ekmfweb.h $(DESTDIR)$(USRINCLUDEDIR)/ekmfweb
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 $(rootdir)include/ekmfweb/ekmfweb.h $(DESTDIR)$(USRINCLUDEDIR)/ekmfweb
install: all $(INSTALL_TARGETS)

View File

@@ -1061,6 +1061,12 @@ int cca_import_key_from_json_web_key(const struct ekmf_cca_lib *cca_lib,
pr_verbose(verbose, "Failed to get and decode x");
goto out;
}
if (len != prime_len) {
/* RFC 7517: Must be full size of a coordinate */
pr_verbose(verbose, "x coordinate length is wrong");
rc = -EINVAL;
goto out;
}
len = prime_len;
rc = json_object_get_base64url(jwk, "y", &q[1 + prime_len],
@@ -1069,6 +1075,12 @@ int cca_import_key_from_json_web_key(const struct ekmf_cca_lib *cca_lib,
pr_verbose(verbose, "Failed to get and decode y");
goto out;
}
if (len != prime_len) {
/* RFC 7517: Must be full size of a coordinate */
pr_verbose(verbose, "y coordinate length is wrong");
rc = -EINVAL;
goto out;
}
rule_array_count = 1;
memcpy(rule_array, "ECC-PUBL", CCA_KEYWORD_SIZE);

View File

@@ -2254,11 +2254,21 @@ int json_web_key_as_pkey(json_object *jwk, int pkey_type, EVP_PKEY **pkey)
rc = json_object_get_base64url(jwk, "x", x, &len);
if (rc != 0)
goto out;
if (len != prime_len) {
/* RFC 7517: Must be full size of a coordinate */
rc = -EINVAL;
goto out;
}
len = prime_len;
rc = json_object_get_base64url(jwk, "y", y, &len);
if (rc != 0)
goto out;
if (len != prime_len) {
/* RFC 7517: Must be full size of a coordinate */
rc = -EINVAL;
goto out;
}
rc = ecc_pub_key_as_pkey(nid, prime_len, x, y, pkey);
if (rc != 0)

View File

@@ -460,7 +460,7 @@ int util_proc_mnt_get_entry(const char *file_name, const char *spec,
rc = scan_mnt_entry(&file, entry);
if (rc)
goto out_free;
if (!strcmp(entry->spec, spec)) {
if (!strcmp(entry->vfstype, spec)) {
rc = 0;
goto out_free;
}

View File

@@ -2,15 +2,27 @@
include ../common.mak
SCRIPTS = mk-s390image mk-pxelinux-ramfs
NETBOOT_SAMPLEDIR=$(TOOLS_DATADIR)/netboot
all:
install: all
$(INSTALL) -d -m 755 $(DESTDIR)$(NETBOOT_SAMPLEDIR)
$(INSTALL) -m 755 mk-s390image mk-pxelinux-ramfs \
$(DESTDIR)$(NETBOOT_SAMPLEDIR)
$(INSTALL) -m 644 Dockerfile Makefile.pxelinux.0 README.md \
install: install-scripts
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 \
Dockerfile Makefile.pxelinux.0 README.md mk-s390image.1 \
$(DESTDIR)$(NETBOOT_SAMPLEDIR)
.PHONY: all install clean
install-scripts: $(SCRIPTS)
@if [ ! -d $(DESTDIR)$(NETBOOT_SAMPLEDIR) ]; then \
mkdir -p $(DESTDIR)$(NETBOOT_SAMPLEDIR); \
chown $(OWNER).$(GROUP) $(DESTDIR)$(NETBOOT_SAMPLEDIR); \
chmod 755 $(DESTDIR)$(NETBOOT_SAMPLEDIR); \
fi; \
for i in $^; do \
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
< $$i >$(DESTDIR)$(NETBOOT_SAMPLEDIR)/$$i; \
chown $(OWNER).$(GROUP) $(DESTDIR)$(NETBOOT_SAMPLEDIR)/$$i; \
chmod 755 $(DESTDIR)$(NETBOOT_SAMPLEDIR)/$$i; \
done
.PHONY: all install clean install-scripts

View File

@@ -21,7 +21,7 @@ ifeq ($(KERNEL_IMAGE),)
$(error Could not find a kernel image under /boot)
endif
BUSYBOX=busybox-1.27.1
BUSYBOX=busybox-1.32.0
BBINSTALL=$(BUSYBOX)/_install
all: $(KERNEL_IMAGE) pxelinux.initramfs

View File

@@ -54,9 +54,18 @@ OPTIONS
-b Search installed busybox in directory BUSYBOX_DIR
-k Use KERNEL_VERSION instead of currently running kernel
-h Print this help, then exit
-v Print version information, then exit
EOF
}
printversion()
{
cat <<-EOD
$cmd: version %S390_TOOLS_VERSION%
Copyright IBM Corp. 2017
EOD
}
# Get shared objects for binary
sharedobjs()
{
@@ -64,7 +73,7 @@ sharedobjs()
}
# Check args
args=$(getopt b:k:h $*)
args=$(getopt b:k:hv $*)
if [ $? = 0 ]
then
set -- $args
@@ -74,6 +83,7 @@ then
-b) busyboxdir=$2; shift 2;;
-k) kernelversion=$2; shift 2;;
-h) usage; exit 0;;
-v) printversion; exit 0;;
--) shift; break;;
*) echo "$cmd: Unexpected argument $1, exiting..." >&2; exit 1;;
esac

View File

@@ -60,9 +60,18 @@ OPTIONS
-p Use PARMFILE with kernel parameters in the image
-r Include RAMDISK in the image
-h Print this help, then exit
-v Print version information, then exit
EOF
}
printversion()
{
cat <<-EOD
$cmd: version %S390_TOOLS_VERSION%
Copyright IBM Corp. 2017
EOD
}
# Convert decimal number to big endian doubleword
dec2be64()
{
@@ -129,6 +138,9 @@ dobuild()
parmfile_size=$(du -b $parmfile | cut -f1)
if [ $parmfile_size -le $MAX_PARMFILE_SIZE ]
then
# Clear any previous parameters
dd seek=$OFFS_COMMANDLINE_BYTES bs=1 count=$MAX_PARMFILE_SIZE \
if=/dev/zero of=$image conv=notrunc status=none
dd seek=$OFFS_COMMANDLINE_BYTES bs=1 if=$parmfile \
of=$image conv=notrunc status=none
else
@@ -142,7 +154,7 @@ dobuild()
}
# check args and build
args=$(getopt "r:p:h" $*)
args=$(getopt "r:p:hv" $*)
if [ $? = 0 ]
then
set -- $args
@@ -152,6 +164,7 @@ then
-r) ramdisk=$2; shift 2;;
-p) parmfile=$2; shift 2;;
-h) usage; exit 0;;
-v) printversion; exit 0;;
--) shift; break;;
*) echo "$cmd: Unexpected argument $1, exiting..." >&2; exit 1;;
esac

17
netboot/mk-s390image.1 Normal file
View File

@@ -0,0 +1,17 @@
.TH MK-S390IMAGE "1" "November 2020" "s390-tools" "User Commands"
.SH NAME
mk-s390image \- tool for creating bootable image
.SH SYNOPSIS
.B mk-s390image
\fI\,KERNEL BOOT_IMAGE \/\fR[\fI\,-r RAMDISK\/\fR] [\fI\,-p PARMFILE\/\fR]
.SH DESCRIPTION
Build an s390 image BOOT_IMAGE suitable for CD/tape/network boot or as a
KVM firmware image using a stripped Linux kernel file KERNEL.
.PP
.SH OPTIONS
.TP
\fB\-p\fR Use PARMFILE with kernel parameters in the image
.TP
\fB\-r\fR Include RAMDISK in the image
.TP
\fB\-h\fR Print usage message, then exit

View File

@@ -227,6 +227,16 @@ sub get_common
# function name or hexadecimal caller address.
#
$line =~ s/<\s+/</;
#
# Since crash 7.2.9 commit
# https://github.com/crash-utility/crash/commit/f1f43bf355df2564543c39f5d7e13b15c67eb13d
# in support of kernel v5.9 commit 0990d836cecb
# ("s390/debug: debug feature version 3"),
# the symbolic caller function name is left aligned instead of right
# aligned, so now we alternatively have to remove whitespace between
# function name and offset.
#
$line =~ s/<([^+> ]+)[ \t]+/<\1/;
@common = split(/\s+/, $line);
#
# Process symbolic kernel module name, if necessary.
@@ -388,6 +398,17 @@ sub get_foreign_records
# caller address.
#
$line =~ s/<\s+/</;
#
# Since crash 7.2.9 commit
# https://github.com/crash-utility/crash/commit/f1f43bf355df2564543c39f5d7e13b15c67eb13d
# in support of kernel v5.9 commit 0990d836cecb
# ("s390/debug: debug feature version 3"),
# the symbolic caller function name is left aligned
# instead of right aligned, so now we alternatively
# have to remove whitespace between function name and
# offset.
#
$line =~ s/<([^+> ]+)[ \t]+/<\1/;
my @raw_rec = split(/\s+/,($line =~ /[|]/) ?
substr($line, 0, index($line, '|')):
$line);

View File

@@ -10,10 +10,11 @@ zipl-switch-to-blscfg \- Switch zipl to use BootLoaderSpec configuration
\fBzipl-switch-to-blscfg\fP {\-h|\-v}
.SH DESCRIPTION
This script switches the zipl boot-loader configuration to use BootLoaderSpec files
to define IPL sections. For each Linux kernel defined in the zipl.conf config file,
a BLS fragment is generated in the BLS directory specified. Also, the zipl.conf is
modified it only contains global configurations, all IPL sections comes from BLS.
This script switches the zipl boot-loader configuration to use BootLoaderSpec
files to define IPL sections. For each Linux kernel defined in the zipl.conf
config file, a BLS fragment is generated in the BLS directory specified. Also,
zipl.conf is modified to only contain global configuration. All IPL sections
come from BLS files.
.SH OPTIONS
.TP
@@ -30,7 +31,8 @@ The suffix used for backup files, defaults to .bak.
.TP
\fB\-\-bls-directory <DIRECTORY>\fP
The DIRECTORY where the BLS fragments will be generated. The directory is created if it doesn't exists, by default /boot/loader/entries is used.
The DIRECTORY where the BLS fragments will be stored. The directory is
created if it does not exist. By default /boot/loader/entries is used.
.TP
\fB\-\-config-file <FILE>\fP

View File

@@ -10,11 +10,12 @@
Description=Apply Control Program Identification (CPI)
DefaultDependencies=no
Conflicts=shutdown.target
After=local-fs.target
After=sysinit.target
ConditionPathIsReadWrite=/sys/firmware/cpi
[Service]
Type=oneshot
RemainAfterExit=yes
#
# Specify a file with the environment variables using the EnvironmentFile=
# service property.

View File

@@ -387,6 +387,7 @@ function extended()
read EXTSZ 2> /dev/null < $DEVPATH/extent_pool/extent_size
read CAPACITY 2> /dev/null < $DEVPATH/capacity/logical_capacity
read ALLOCATED 2> /dev/null < $DEVPATH/capacity/space_allocated
read FC_SEC 2> /dev/null < $DEVPATH/fc_security
# convert to hexadecimal values
PIM=0x$PIM
@@ -521,7 +522,7 @@ function extended()
elif [[ "$ALIAS" == 1 ]]; then
if [[ "$BASEONLY" == "false" ]]; then
ACTIVE="alias"
printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s # uid: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
printf "%s:%s:%s# status:\t\t\t\t%s# type: \t\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s # uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
"$SORTKEYLEN" "$SORTKEY" \
"$BUSID" \
"$ACTIVE" \
@@ -532,6 +533,7 @@ function extended()
"$ERP" \
"$HPF" \
"$DEV_UID" \
"$FC_SEC" \
"${INSTALLED_PATHS[@]}" \
"${USED_PATHS[@]}" \
"${NP_PATHS[@]}" \
@@ -563,7 +565,7 @@ function extended()
DISCIPLINE="${DISCIPLINE} (ESE)"
fi
printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# extent_size:\t\t\t\t%s# logical_capacity:\t\t\t%s# space_allocated:\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
printf "%s:%s:%s/%s/%s%s%s# status:\t\t\t\t%s# type: \t\t\t\t%s# blksz:\t\t\t\t%s# size: \t\t\t\t%s# blocks:\t\t\t\t%s# extent_size:\t\t\t\t%s# logical_capacity:\t\t\t%s# space_allocated:\t\t\t%s# use_diag:\t\t\t\t%s# readonly:\t\t\t\t%s# eer_enabled:\t\t\t\t%s# erplog:\t\t\t\t%s# hpf:\t\t\t\t\t%s# uid: \t\t\t\t%s# fc_security: \t\t\t\t%s# paths_installed: \t\t\t%s %s %s %s %s %s %s %s# paths_in_use: \t\t\t%s %s %s %s %s %s %s %s# paths_non_preferred: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_cabling: \t\t%s %s %s %s %s %s %s %s# paths_cuir_quiesced: \t\t\t%s %s %s %s %s %s %s %s# paths_invalid_hpf_characteristics: \t%s %s %s %s %s %s %s %s# paths_error_threshold_exceeded: \t%s %s %s %s %s %s %s %s#\n" \
"$SORTKEYLEN" "$SORTKEY" \
"$BUSID" \
"$BLOCKNAME" \
@@ -584,6 +586,7 @@ function extended()
"$ERP" \
"$HPF" \
"$DEV_UID" \
"$FC_SEC" \
"${INSTALLED_PATHS[@]}" \
"${USED_PATHS[@]}" \
"${NP_PATHS[@]}" \

View File

@@ -1178,8 +1178,14 @@ static int get_apqn_measurement_data(uint8_t card)
scdmd_area.request.header.code = 0x102d;
scdmd_area.request.header.length =
sizeof(struct chsc_scdmd_request);
scdmd_area.request.first_drid.ap_index = card;
scdmd_area.request.first_drid.domain_index = g.min_domain;
if (scdmd_area.response.p) {
scdmd_area.request.first_drid =
scdmd_area.response.crid;
} else {
scdmd_area.request.first_drid.ap_index = card;
scdmd_area.request.first_drid.domain_index =
g.min_domain;
}
scdmd_area.request.last_drid.ap_index = card;
scdmd_area.request.last_drid.domain_index = g.max_domain;
scdmd_area.request.s = 1;
@@ -1217,10 +1223,6 @@ static int get_apqn_measurement_data(uint8_t card)
rc = process_apqn_measurement_data(&scdmd_area);
if (rc != 0)
break;
if (scdmd_area.response.p)
scdmd_area.request.first_drid =
scdmd_area.response.crid;
} while (scdmd_area.response.p);
return rc;

View File

@@ -12,6 +12,6 @@
#include "exit_code.h"
exit_code_t root_check(void);
exit_code_t initrd_check(bool all_pers);
#endif /* ROOT_H */

View File

@@ -4,6 +4,16 @@ include ../../common.mak
ALL_CPPFLAGS += -I ../include -std=gnu99 -Wno-unused-parameter \
-Wno-missing-field-initializers
# Adding ZDEV_ALWAYS_UPDATE_INITRD=1 option will update the initial RAM-disk
# without the user interaction upon the modification of a persistent device
# configuration.
ifeq ($(ZDEV_ALWAYS_UPDATE_INITRD),1)
ALL_CPPFLAGS += -DZDEV_ALWAYS_UPDATE_INITRD=true
else
ALL_CPPFLAGS += -DZDEV_ALWAYS_UPDATE_INITRD=false
endif
# Core
chzdev_objects += attrib.o chzdev.o device.o devnode.o devtype.o exit_code.o \
export.o hash.o inuse.o misc.o namespace.o opts.o path.o \

View File

@@ -3027,7 +3027,7 @@ int main(int argc, char *argv[])
!dryrun) {
/* If the root device/device type or early devices have been
* modified, additional work might be necessary. */
rc = root_check();
rc = initrd_check(ZDEV_ALWAYS_UPDATE_INITRD);
if (rc && !drc)
drc = rc;
}

View File

@@ -313,6 +313,22 @@ static struct attrib dasd_attr_safe_offline = {
.writeonly = 1,
};
static struct attrib dasd_attr_fc_security = {
.name = "fc_security",
.title = "Show FC Endpoint Security state of DASD device",
.desc =
"This read-only attribute shows the Fibre Channel Endpoint Security\n"
"status of the connection to the DASD device:\n"
" Unsupported : The DASD device does not support Fibre Channel\n"
" Endpoint Security\n"
" Inconsistent : The operational channel paths of the DASD device\n"
" report inconsistent Fibre Channel Endpoint\n"
" Security status\n"
" Authentication: The connection has been authenticated\n"
" Encryption : The connection is encrypted\n",
.readonly = 1,
};
/*
* DASD subtype methods.
*/
@@ -617,6 +633,7 @@ struct subtype dasd_subtype_eckd = {
&dasd_attr_reservation_policy,
&dasd_attr_last_known_reservation_state,
&dasd_attr_safe_offline,
&dasd_attr_fc_security,
&internal_attr_early,
),
.unknown_dev_attribs = 1,

View File

@@ -58,11 +58,50 @@ static void add_early_removed(struct util_list *selected)
}
}
static void add_pers_removed(struct util_list *strlist)
{
int i, j;
struct devtype *dt;
struct subtype *st;
struct device *dev;
for (i = 0; devtypes[i]; i++) {
dt = devtypes[i];
for (j = 0; dt->subtypes[j]; j++) {
st = dt->subtypes[j];
util_list_iterate(&st->devices->hash.list, dev) {
if (dev->persistent.deconfigured) {
strlist_add(strlist, "%s %s",
dev->subtype->devname, dev->id);
}
}
}
}
}
static bool is_zdev_early_0(struct selected_dev_node *sel)
{
struct setting *s;
struct device *dev;
dev = device_list_find(sel->st->devices, sel->id, NULL);
if (!dev)
return false;
s = setting_list_find(dev->persistent.settings,
internal_attr_early.name);
if (!s)
return false;
if (s->specified && strcmp(s->value, "0") == 0)
return true;
return false;
}
/* Determine if initial RAM-disk needs updating. If so, run the corresponding
* scripts if available. */
exit_code_t root_check(void)
exit_code_t initrd_check(bool all_pers)
{
struct util_list *selected, *params, *mod = NULL;
struct util_list *selected, *params, *mod = strlist_new();
struct selected_dev_node *sel;
struct device *dev;
char *params_str;
@@ -76,6 +115,20 @@ exit_code_t root_check(void)
/* Get list of devices that provide the root device or require
* early configuration. */
selected = selected_dev_list_new();
if (all_pers) {
/* Add all persistently configured devices. */
select = select_opts_new();
select->configured = 1;
select_devices(select, selected, 1, 0, 0, config_persistent,
scope_mandatory, err_ignore);
select_opts_free(select);
/* Ensure that removed devices are considered. */
add_pers_removed(mod);
goto check_mod;
}
/* First add devices that had zdev:early removed or changed to 0.
* The subsequent call to select_devices() will filter out any
* duplicates. */
@@ -95,8 +148,8 @@ exit_code_t root_check(void)
err_ignore);
select_opts_free(select);
check_mod:
/* Determine if any of the devices or device types has been modified. */
mod = strlist_new();
util_list_iterate(selected, sel) {
dt = sel->st->devtype;
@@ -127,17 +180,22 @@ exit_code_t root_check(void)
goto out;
}
/* Ask for confirmation. */
if (!confirm("Update initial RAM-disk now?")) {
rc = EXIT_ABORTED;
goto out;
if (!all_pers) {
/* Ask for confirmation. */
if (!confirm("Update initial RAM-disk now?")) {
rc = EXIT_ABORTED;
goto out;
}
}
/* Build the command line. */
params = strlist_new();
util_list_iterate(selected, sel) {
strlist_add(params, "%s", sel->st->name);
strlist_add(params, "%s", sel->id);
/* From the selected list, remove the devices with zdev:early=0 */
if (!is_zdev_early_0(sel)) {
strlist_add(params, "%s", sel->st->name);
strlist_add(params, "%s", sel->id);
}
}
params_str = strlist_flatten(params, " ");
strlist_free(params);

View File

@@ -407,7 +407,7 @@ void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
if (size == 0)
return;
mem_chunk_create(&l.mem_phys, start, size, data, read_fn, free_fn);
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, NULL);
l.mem_virt.chunk_cache->volnr = volnr;
}

View File

@@ -42,6 +42,8 @@ static int pt_load_add(Elf64_Phdr *phdr)
STDERR("Dump file \"%s\" is a user space core dump\n",
g.opts.device);
}
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
return -EINVAL;
if (phdr->p_filesz == 0) {
/* Add zero memory chunk */
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, NULL,
@@ -52,8 +54,6 @@ static int pt_load_add(Elf64_Phdr *phdr)
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, off_ptr,
dfi_elf_mem_chunk_read_fn, zg_free);
}
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
return -EINVAL;
return 0;
}

View File

@@ -280,6 +280,9 @@ off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check)
{
off_t rc;
if (off >= zg_fh->sb.st_size)
ERR_EXIT("Trying to seek past file end \"%s\"", zg_fh->path);
rc = lseek(zg_fh->fh, off, SEEK_SET);
if (rc == -1 && check != ZG_CHECK_NONE)
ERR_EXIT_ERRNO("Could not seek \"%s\"", zg_fh->path);

View File

@@ -3,6 +3,9 @@ include ../common.mak
CPIOINIT = $(call echocmd," CPIOINI ",/$@)./cpioinit
INSTALL_SCRIPTS = 10-zfcpdump.install
ALL_CFLAGS += -fno-sanitize=all
ALL_LDFLAGS += -fno-sanitize=all
ifeq (${HAVE_LIBC_STATIC},0)
all:

View File

@@ -10,7 +10,8 @@ ALL_CFLAGS = $(NO_PIE_CFLAGS) -Os -g $(INCLUDE_PARMS) \
-fno-delete-null-pointer-checks -fno-stack-protector \
-fexec-charset=IBM1047 -m64 -mpacked-stack \
-mstack-size=4096 -mstack-guard=128 -msoft-float \
-W -Wall -Wformat-security
-W -Wall -Wformat-security -fno-sanitize=all
ALL_LDFLAGS += -fno-sanitize=all
FILES = fba0.bin fba1b.bin fba2.bin \
eckd0_ldl.bin eckd0_cdl.bin \

View File

@@ -449,13 +449,14 @@ void readblock(unsigned long blk, unsigned long addr, unsigned long blk_count)
* block number
*/
unsigned long write_dump_segment(unsigned long blk,
struct df_s390_dump_segm_hdr *segm,
unsigned long zero_page)
struct df_s390_dump_segm_hdr *segm)
{
unsigned long addr, start_blk, blk_count;
unsigned long addr, start_blk, blk_count, zero_page;
/* Write the dump segment header itself (1 page) */
zero_page = get_zeroed_page();
writeblock(blk, (unsigned long)segm, m2b(PAGE_SIZE), zero_page);
free_page(zero_page);
blk += m2b(PAGE_SIZE);
/* Write the dump segment */
addr = segm->start;
@@ -464,7 +465,9 @@ unsigned long write_dump_segment(unsigned long blk,
/* Remaining blocks to write */
blk_count = m2b(segm->len) - (blk - start_blk);
blk_count = MIN(blk_count, eckd_blk_max);
zero_page = get_zeroed_page();
writeblock(blk, addr, blk_count, zero_page);
free_page(zero_page);
progress_print(addr);
blk += blk_count;
addr += b2m(blk_count);

View File

@@ -48,7 +48,6 @@ void writeblock(unsigned long blk, unsigned long addr, unsigned long blk_count,
unsigned long zero_page);
void readblock(unsigned long blk, unsigned long addr, unsigned long blk_count);
unsigned long write_dump_segment(unsigned long blk,
struct df_s390_dump_segm_hdr *segm,
unsigned long zero_page);
struct df_s390_dump_segm_hdr *segm);
#endif /* ECKD2DUMP_H */

View File

@@ -192,10 +192,13 @@ void dt_device_enable(void)
* Check for the volume timestamp and validate the dump signature
* before writing a dump.
*/
static void check_volume(unsigned long page)
static void check_volume(void)
{
struct mvdump_parm_table *mvdump_table_new;
struct df_s390_hdr *hdr_new;
unsigned long page;
page = get_zeroed_page();
/*
* Check whether parameter table on dump device has a valid
@@ -222,6 +225,8 @@ static void check_volume(unsigned long page)
if (dump_hdr->magic != hdr_new->mvdump_sign)
panic(ENOSIGN, "Wrong signature");
}
free_page(page);
}
/*
@@ -229,10 +234,10 @@ static void check_volume(unsigned long page)
* address to write for the next volume or memory size if the dump ended
* on this volume
*/
static unsigned long write_volume(unsigned long addr, unsigned long page,
static unsigned long write_volume(unsigned long addr,
struct df_s390_dump_segm_hdr *dump_segm)
{
unsigned long free_space, blk;
unsigned long free_space, blk, page;
/*
* Write dump header
@@ -245,7 +250,7 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
* header and the end marker)
*/
free_space = b2m(device.blk_end - blk + 1) - b2m(2);
memset((void *) page, 0, PAGE_SIZE);
/*
* Write dump data
*/
@@ -257,7 +262,7 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
addr = find_dump_segment(addr, dump_hdr->mem_size,
ROUND_DOWN(free_space, MIB),
dump_segm);
blk = write_dump_segment(blk, dump_segm, page);
blk = write_dump_segment(blk, dump_segm);
/* Update free space left on vol */
free_space -= dump_segm->len;
/* Reserve one block for the next segment header */
@@ -267,8 +272,10 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
/* Check if no more dump segments follow */
if (dump_segm->stop_marker) {
/* Write end marker */
page = get_zeroed_page();
df_s390_em_page_init(page);
writeblock(blk, page, 1, 0);
free_page(page);
return dump_hdr->mem_size;
}
/*
@@ -286,19 +293,18 @@ static unsigned long write_volume(unsigned long addr, unsigned long page,
void dt_dump_mem(void)
{
struct df_s390_dump_segm_hdr *dump_segm;
unsigned long addr, page;
unsigned long addr;
dump_hdr->mvdump_sign = DF_S390_MAGIC_EXT;
dump_hdr->mvdump = 1;
addr = 0;
total_dump_size = 0;
page = get_zeroed_page();
dump_segm = (void *)get_zeroed_page();
while (1) {
printf("Dumping to: 0.%x.%04x", device.sid.ssid, device.devno);
check_volume(page);
addr = write_volume(addr, page, dump_segm);
check_volume();
addr = write_volume(addr, dump_segm);
if (addr == dump_hdr->mem_size)
break;
/*
@@ -312,7 +318,6 @@ void dt_dump_mem(void)
set_device(device.sid, DISABLED);
dt_device_enable();
}
progress_print(addr);
free_page(page);
free_page(__pa(dump_segm));
progress_print(addr);
}

View File

@@ -66,7 +66,6 @@ void dt_dump_mem(void)
struct df_s390_dump_segm_hdr *dump_segm;
blk = device.blk_start;
page = get_zeroed_page();
dump_segm = (void *)get_zeroed_page();
/* Write dump header */
@@ -79,18 +78,19 @@ void dt_dump_mem(void)
end = dump_hdr->mem_size;
while (addr < end) {
addr = find_dump_segment(addr, end, 0, dump_segm);
blk = write_dump_segment(blk, dump_segm, page);
blk = write_dump_segment(blk, dump_segm);
total_dump_size += dump_segm->len;
if (dump_segm->stop_marker) {
addr = end;
break;
}
}
free_page(__pa(dump_segm));
progress_print(addr);
/* Write end marker */
page = get_zeroed_page();
df_s390_em_page_init(page);
writeblock(blk, page, 1, 0);
free_page(page);
free_page(__pa(dump_segm));
}

View File

@@ -141,13 +141,14 @@ static void writeblock_fba(unsigned long blk, unsigned long addr,
* block number
*/
unsigned long write_dump_segment_fba(unsigned long blk,
struct df_s390_dump_segm_hdr *dump_segm,
unsigned long zero_page)
struct df_s390_dump_segm_hdr *dump_segm)
{
unsigned long addr, start_blk, blk_count;
unsigned long addr, start_blk, blk_count, zero_page;
/* Write the dump segment header itself (1 page) */
zero_page = get_zeroed_page();
writeblock_fba(blk, __pa(dump_segm), BLK_PER_PAGE, zero_page);
free_page(zero_page);
blk += BLK_PER_PAGE;
/* Write the dump segment */
addr = dump_segm->start;
@@ -156,7 +157,9 @@ unsigned long write_dump_segment_fba(unsigned long blk,
/* Remaining blocks to write */
blk_count = m2b(dump_segm->len) - (blk - start_blk);
blk_count = MIN(blk_count, BLK_PWRT);
zero_page = get_zeroed_page();
writeblock_fba(blk, addr, blk_count, zero_page);
free_page(zero_page);
progress_print(addr);
blk += blk_count;
addr += b2m(blk_count);
@@ -198,7 +201,6 @@ void dt_dump_mem(void)
ccw_program_init();
blk = device.blk_start;
page = get_zeroed_page();
dump_segm = (void *)get_zeroed_page();
/* Write dump header */
@@ -211,18 +213,19 @@ void dt_dump_mem(void)
end = dump_hdr->mem_size;
while (addr < end) {
addr = find_dump_segment(addr, end, 0, dump_segm);
blk = write_dump_segment_fba(blk, dump_segm, page);
blk = write_dump_segment_fba(blk, dump_segm);
total_dump_size += dump_segm->len;
if (dump_segm->stop_marker) {
addr = end;
break;
}
}
free_page(__pa(dump_segm));
progress_print(addr);
/* Write end marker */
page = get_zeroed_page();
df_s390_em_page_init(page);
writeblock_fba(blk, page, 1, 0);
free_page(page);
free_page(__pa(dump_segm));
}

View File

@@ -32,9 +32,10 @@ struct ex_table_entry {
};
#define MEM_ALLOC_START ((unsigned long) __heap_start)
#define MEM_ALLOC_CNT 4
#define MEM_ALLOC_END ((unsigned long) __heap_stop)
#define MEM_ALLOC_MAX 4
static uint8_t mem_page_alloc_vec[MEM_ALLOC_CNT];
static uint8_t mem_page_alloc_vec[MEM_ALLOC_MAX];
/*
* Initialize memory with value
@@ -417,10 +418,11 @@ void printf(const char *fmt, ...)
*/
unsigned long get_zeroed_page(void)
{
const int page_count = MIN(MEM_ALLOC_MAX, (int)((MEM_ALLOC_END - MEM_ALLOC_START) / PAGE_SIZE));
unsigned long addr;
int i;
for (i = 0; i < MEM_ALLOC_CNT; i++) {
for (i = 0; i < page_count; i++) {
if (mem_page_alloc_vec[i] != 0)
continue;
addr = MEM_ALLOC_START + i * PAGE_SIZE;
@@ -436,6 +438,9 @@ unsigned long get_zeroed_page(void)
*/
void free_page(unsigned long addr)
{
if (addr < MEM_ALLOC_START || addr >= MEM_ALLOC_END)
libc_stop(EINTERNAL);
mem_page_alloc_vec[(addr - MEM_ALLOC_START) / PAGE_SIZE] = 0;
}

View File

@@ -90,6 +90,7 @@ void start(void)
void *load_address;
struct component_entry *entry;
disk_blockptr_t *blockptr;
uint64_t load_psw;
void *load_page;
int config_nr;
@@ -133,11 +134,13 @@ void start(void)
if (entry->type != COMPONENT_EXECUTE)
panic(EWRONGTYPE, "");
load_psw = entry->address.load_psw;
free_page((unsigned long)load_page);
io_irq_disable();
set_device(subchannel_id, DISABLED);
execute(entry->address.load_psw);
execute(load_psw);
}
void panic_notify(unsigned long UNUSED(reason))

View File

@@ -444,6 +444,9 @@ type_determined:
}
/* Convert device size to size in physical blocks */
data->phy_blocks = devsize / (data->phy_block_size / 512);
/* Adjust start on SCSI according to block_size. device-mapper devices are skipped */
if (data->type == disk_type_scsi && target->targetbase == NULL)
data->geo.start = data->geo.start / (data->phy_block_size / 512);
if (data->partnum != 0)
data->partition = stats.st_rdev;
/* Try to get device name */

View File

@@ -34,6 +34,8 @@ endif
libs = $(rootdir)/libutil/libutil.a
CFLAGS += -DKMS_PLUGIN_LOCATION=\"$(ZKEYKMSPLUGINDIR)\"
detect-libcryptsetup.dep:
echo "#include <libcryptsetup.h>" > detect-libcryptsetup.dep
echo "#ifndef CRYPT_LUKS2" >> detect-libcryptsetup.dep

View File

@@ -7,8 +7,6 @@ all: zkey-ekmfweb.so
libs = $(rootdir)/libutil/libutil.a
export LIBRARY_PATH = $(rootdir)/libekmfweb:$LIBRARY_PATH
zkey-ekmfweb.o: zkey-ekmfweb.c zkey-ekmfweb.h ../kms-plugin.h \
../cca.h ../utils.h ../pkey.h ../properties.h \
$(rootdir)include/ekmfweb/ekmfweb.h libekmfweb.dep
@@ -29,7 +27,7 @@ utils.o: ../utils.c ../utils.h ../pkey.h ../cca.h ../ep11.h
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -fPIC -c $< -o $@
zkey-ekmfweb.so: ALL_CFLAGS += -fPIC
zkey-ekmfweb.so: LDLIBS = -lekmfweb -ldl -lcrypto
zkey-ekmfweb.so: LDLIBS = -L$(rootdir)/libekmfweb -lekmfweb -ldl -lcrypto
zkey-ekmfweb.so: ALL_LDFLAGS += -shared -Wl,--version-script=zkey-ekmfweb.map \
-Wl,-z,defs,-Bsymbolic -Wl,-soname,zkey-ekmfweb.so.$(VERM)
zkey-ekmfweb.so: zkey-ekmfweb.o properties.o pkey.o cca.o ep11.o utils.o $(libs)
@@ -46,9 +44,8 @@ libekmfweb.dep:
install: all install-libekmfweb.dep zkey-ekmfweb.so
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
$(INSTALL) -m 644 -c zkey-ekmfweb.1 $(DESTDIR)$(MANDIR)/man1
$(INSTALL) -d -m 755 $(DESTDIR)$(USRLIB64DIR)
$(INSTALL) -d -m 755 $(DESTDIR)$(USRLIB64DIR)/zkey
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T zkey-ekmfweb.so $(DESTDIR)$(USRLIB64DIR)/zkey/zkey-ekmfweb.so
$(INSTALL) -d -m 755 $(DESTDIR)$(ZKEYKMSPLUGINDIR)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 -T zkey-ekmfweb.so $(DESTDIR)$(ZKEYKMSPLUGINDIR)/zkey-ekmfweb.so
clean:
rm -f *.o zkey-ekmfweb.so install-libekmfweb.dep libekmfweb.dep

View File

@@ -321,7 +321,7 @@ Specifies the subject name for generating a certificate signing request (CSR)
or self signed certificate, in the form
\fB<type>=<value>(;<type>=<value>)*[;]\fP with types recognized by OpenSSL.
.TP
.BR \-s ", " \-\-cert\-extensions\~\fIextensions\fP
.BR \-e ", " \-\-cert\-extensions\~\fIextensions\fP
Specifies the certificate extensions for generating a certificate signing
request (CSR) or self signed certificate, in the form
\fB<name>=[critical,]<value(s)>(;<name>=[critical,]<value(s)>)*[;]\fP
@@ -416,7 +416,7 @@ Configures the connection to the EKMF Web server on 'my.ekmfweb.server'.
.B zkey kms configure \-\-ekmfweb\-url https://my.ekmfweb.server \-\-tls\-pin\-server\-pubkey \-\-tls\-verify\-hostname
Configures the connection to the EKMF Web server on 'my.ekmfweb.server' and
pins the server's public key from the server's TSL certificate as well as
enables verification of the host nmae to match the server's Common Name in the
enables verification of the host name to match the server's Common Name in the
certificate.
.TP
.B zkey kms configure \-\-gen\-csr csr.pem \-\-cert\-subject \(dqCN=my.zkey.client;OU=Example;C=US\(dq
@@ -437,10 +437,10 @@ subject name and a certificate extension to limit the key usage, and stores it
in file 'cert.pem'.
.TP
.B zkey kms configure \-\-register cert.pem
Registers the zkey client with EKMF Web using the certifcate in file 'cert.pem'.
Registers the zkey client with EKMF Web using the certificate in file 'cert.pem'.
.TP
.B zkey kms configure \-\-register cert.pem \-\-label\-tags \(dqENV=TEST,APP=LINUX\(dq
Registers the zkey client with EKMF Web using the certifcate in file 'cert.pem'
Registers the zkey client with EKMF Web using the certificate in file 'cert.pem'
and the label tags 'ENV=TEST' and 'APP=LINUX' for the identity key.
.TP
.B zkey kms info
@@ -480,7 +480,7 @@ client is allowed to use it or not.
.TP
.B zkey kms list \-\-label \(dq*LUKS2*\(dq
Displays eligible secure keys managed by EKMF Web where the label name in EKMF
Web contains the work 'LUKS2'.
Web contains the word 'LUKS2'.
.TP
.B zkey kms import \-\-name seckey
Imports the secure key managed by EKMF Web with a zkey name of 'seckey'.

View File

@@ -899,24 +899,24 @@ int kms_display_info(const kms_handle_t handle)
if (rc == 0) {
switch (type) {
case EVP_PKEY_EC:
printf(" EBMF Web public key: ECC (%s)\n",
printf(" EKMF Web public key: ECC (%s)\n",
OBJ_nid2sn(curve));
break;
case EVP_PKEY_RSA:
printf(" EBMF Web public key: RSA "
printf(" EKMF Web public key: RSA "
"(%d bits)\n", mod_bits);
break;
default:
printf(" EBMF Web public key: "
printf(" EKMF Web public key: "
"(unknown key type)\n");
break;
}
} else {
printf(" EBMF Web public key: (not available)\n");
printf(" EKMF Web public key: (not available)\n");
}
free(tmp);
} else {
printf(" EBMF Web public key: (configuration required)\n");
printf(" EKMF Web public key: (configuration required)\n");
}
printf(" Key templates:\n");
@@ -2520,7 +2520,7 @@ static int _configure_connection(struct plugin_handle *ph,
"[y/N]? ",
program_invocation_short_name);
if (!prompt_for_yes(ph->verbose)) {
_set_error(ph, "Opertion aborted by user");
_set_error(ph, "Operation aborted by user");
return -ECANCELED;
}
}
@@ -2651,10 +2651,10 @@ static int _configure_connection(struct plugin_handle *ph,
goto out;
}
}
printf("%s: Is this the EKMF Web server you intent to work with "
printf("%s: Is this the EKMF Web server you intend to work with "
"[y/N]? ", program_invocation_short_name);
if (!prompt_for_yes(ph->verbose)) {
_set_error(ph, "Opertion aborted by user");
_set_error(ph, "Operation aborted by user");
rc = -ECANCELED;
goto out;
}
@@ -2948,7 +2948,7 @@ static int _generate_identity_key(struct plugin_handle *ph)
printf("%s: Re-generate the identity key [y/N]? ",
program_invocation_short_name);
if (!prompt_for_yes(ph->verbose)) {
_set_error(ph, "Opertion aborted by user");
_set_error(ph, "Operation aborted by user");
return -ECANCELED;
}
} else {
@@ -3347,45 +3347,6 @@ static void _free_ekmf_tags(struct ekmf_tag_list *ekmf_tag_list)
ekmf_tag_list->num_tags = 0;
}
/**
* Gets the next sequence number of the template
*
* @param ph the plugin handle
* @param template_uuid the template UUID
*
* @returns an allocated string, or NULL in case of an error.
*/
static char *_get_seqno(struct plugin_handle *ph, const char *template_uuid)
{
unsigned int seqno = 0;
char *error_msg = NULL;
char *ret = NULL;
int rc;
rc = ekmf_get_last_seq_no(&ph->ekmf_config, &ph->curl_handle,
template_uuid, &seqno, &error_msg,
ph->verbose);
if (rc != 0) {
_set_error(ph, "Failed to get last used sequence number for "
"template '%s': %s",
template_uuid, error_msg != NULL ? error_msg :
strerror(-rc));
_remove_login_token_if_error(ph, rc);
goto out;
}
seqno++;
util_asprintf(&ret, "%05u", seqno);
pr_verbose(ph, "Seqno: '%s'", ret);
out:
if (error_msg != NULL)
free(error_msg);
return ret;
}
/**
* Parses the label tags passed in via option (<tag>=<value>;<tag>=<value;....)
* and allocates an array of KMS properties. The tags must be freed by the
@@ -3450,25 +3411,16 @@ static int _parse_label_tags(struct plugin_handle *ph,
if (value != NULL) {
ekmf_tag_list->tags[i].value =
util_strdup(value);
util_str_toupper((char *)
ekmf_tag_list->tags[i].value);
} else {
ekmf_tag_list->tags[i].value =
_get_seqno(ph,
template_info->uuid);
if (ekmf_tag_list->tags[i].value ==
NULL) {
rc = -EIO;
goto out;
}
util_strdup(EKMFWEB_SEQNO_NEXT);
}
k++;
} else {
ekmf_tag_list->tags[i].value =
_get_seqno(ph,
template_info->uuid);
if (ekmf_tag_list->tags[i].value == NULL) {
rc = -EIO;
goto out;
}
util_strdup(EKMFWEB_SEQNO_NEXT);
}
} else {
if (tag == NULL) {
@@ -3504,11 +3456,10 @@ static int _parse_label_tags(struct plugin_handle *ph,
}
ekmf_tag_list->tags[i].value = util_strdup(value);
util_str_toupper((char *)ekmf_tag_list->tags[i].value);
k++;
}
util_str_toupper((char *)ekmf_tag_list->tags[i].value);
pr_verbose(ph, "Tag: '%s', Value: '%s'",
ekmf_tag_list->tags[i].name,
ekmf_tag_list->tags[i].value);
@@ -3649,7 +3600,7 @@ static int _register_client(struct plugin_handle *ph, const char *cert_file,
printf("%s: Re-register the zkey client [y/N]? ",
program_invocation_short_name);
if (!prompt_for_yes(ph->verbose)) {
_set_error(ph, "Opertion aborted by user");
_set_error(ph, "Operation aborted by user");
return -ECANCELED;
}
}
@@ -4566,22 +4517,23 @@ static int _properties_to_ekmf_tags(struct plugin_handle *UNUSED(ph),
struct ekmf_tag_list *ekmf_tag_list,
bool null_values_only)
{
size_t i;
size_t i, k;
ekmf_tag_list->num_tags = 0;
ekmf_tag_list->tags = util_malloc(
sizeof(struct ekmf_tag) * num_properties);
for (i = 0; i < num_properties; i++) {
for (i = 0, k = 0; i < num_properties; i++) {
if (!null_values_only && properties[i].value == NULL)
continue;
if (null_values_only && properties[i].value != NULL)
continue;
ekmf_tag_list->tags[i].name = util_strdup(properties[i].name);
ekmf_tag_list->tags[i].value = properties[i].value != NULL ?
ekmf_tag_list->tags[k].name = util_strdup(properties[i].name);
ekmf_tag_list->tags[k].value = properties[i].value != NULL ?
util_strdup(properties[i].value) : NULL;
ekmf_tag_list->num_tags++;
k++;
}
return 0;
@@ -4981,10 +4933,10 @@ int kms_set_key_properties(const kms_handle_t handle, const char *key_id,
for (i = 0; i < num_properties; i++) {
util_assert(properties[i].name != NULL,
"Internal error: property name is NULL");
util_assert(properties[i].value != NULL,
"Internal error: property value is NULL");
pr_verbose(ph, " Property '%s': '%s", properties[i].name,
properties[i].value);
pr_verbose(ph, " Property '%s': '%s'", properties[i].name,
properties[i].value != NULL ? properties[i].value :
"(null)");
}
_clear_error(ph);

View File

@@ -99,6 +99,7 @@ struct plugin_handle {
#define EKMFWEB_CURVE_PRIME "PRIME_CURVE"
#define EKMFWEB_CURVE_BAINPOOL "BRAINPOOL_CURVE"
#define EKMFWEB_SEQNO_TAG "seqno"
#define EKMFWEB_SEQNO_NEXT "next"
#define DEFAULT_IDENTITY_KEY_PUBLIC_EXPONENT 65537

View File

@@ -40,12 +40,16 @@ struct key_filenames {
char *skey_filename;
char *info_filename;
char *renc_filename;
char *pass_filename;
};
#define FILE_EXTENSION_LEN 5
#define SKEY_FILE_EXTENSION ".skey"
#define INFO_FILE_EXTENSION ".info"
#define RENC_FILE_EXTENSION ".renc"
#define PASS_FILE_EXTENSION ".pass"
#define DUMMY_PASSPHRASE_LEN 16
#define LOCK_FILE_NAME ".lock"
@@ -76,6 +80,7 @@ struct key_filenames {
#define REC_VOLUME_TYPE "Volume type"
#define REC_KMS "KMS"
#define REC_KMS_KEY_LABEL "KMS key label"
#define REC_PASSPHRASE_FILE "Dummy passphrase"
#define pr_verbose(keystore, fmt...) do { \
if (keystore->verbose) \
@@ -110,6 +115,8 @@ static int _keystore_get_key_filenames(struct keystore *keystore,
name, INFO_FILE_EXTENSION);
util_asprintf(&names->renc_filename, "%s/%s%s", keystore->directory,
name, RENC_FILE_EXTENSION);
util_asprintf(&names->pass_filename, "%s/%s%s", keystore->directory,
name, PASS_FILE_EXTENSION);
pr_verbose(keystore, "File names for key '%s': '%s' and '%s'", name,
names->skey_filename, names->info_filename);
@@ -128,6 +135,18 @@ static int _keystore_reencipher_key_exists(struct key_filenames *file_names)
return util_path_is_reg_file("%s", file_names->renc_filename);
}
/**
* Checks if the .pass file exists.
*
* @param[in] file_names names of the files
*
* @returns 1 if the file exist, 0 if the file do not exist
*/
static int _keystore_passphrase_file_exists(struct key_filenames *file_names)
{
return util_path_is_reg_file("%s", file_names->pass_filename);
}
/**
* Checks if both, the .skey and the .info (and .renc) files exist.
*
@@ -146,7 +165,8 @@ static int _keystore_exists_keyfiles(struct key_filenames *file_names)
if (rc_skey && rc_info)
return 1;
if (!rc_skey && !rc_info &&
_keystore_reencipher_key_exists(file_names) == 0)
_keystore_reencipher_key_exists(file_names) == 0 &&
_keystore_passphrase_file_exists(file_names) == 0)
return 0;
return -1;
}
@@ -220,6 +240,8 @@ static void _keystore_free_key_filenames(struct key_filenames *names)
free(names->info_filename);
if (names->renc_filename)
free(names->renc_filename);
if (names->pass_filename)
free(names->pass_filename);
}
/**
@@ -985,7 +1007,7 @@ static int _keystore_process_filtered(struct keystore *keystore,
process_key_t process_func,
void *process_private)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
char **apqn_filter_list = NULL;
char **vol_filter_list = NULL;
struct properties *key_props;
@@ -1593,6 +1615,129 @@ static int _keystore_set_default_properties(struct properties *key_props)
return 0;
}
/**
* Generate, Set or remove a dummy LUKS2 passphrase of a key.
*
* @param[in] keystore the key store
* @param[in] name the name of the key
* @param[in] file_names the file names of the key
* @param[in] properties the properties of the key
* @param[in] prompt if true, prompt for removal (if passphrase exists)
*
* @returns 0 on success, or a negative errno value on error
*/
static int _keystore_remove_passphrase(struct keystore *keystore,
const char *name,
const struct key_filenames *filenames,
struct properties *properties,
bool prompt)
{
int rc;
if (_keystore_passphrase_file_exists((struct key_filenames *)filenames)
&& prompt) {
util_print_indented("ATTENTION: When you remove the LUKS2 "
"dummy passphrase of a key, you might no "
"longer be able to open the LUKS2 volumes "
"associated with the key, unless you still "
"know a passphrase of one of the key slots "
"of these volumes!", 0);
_keystore_msg_for_volumes("The following volumes are encrypted "
"with this key:", properties, NULL);
printf("%s: Remove passphrase for key '%s' [y/N]? ",
program_invocation_short_name, name);
if (!prompt_for_yes(keystore->verbose)) {
warnx("Operation aborted");
return -ECANCELED;
}
}
rc = remove(filenames->pass_filename);
if (rc != 0 && errno != ENOENT) {
rc = -errno;
warnx("Failed to remove file '%s': %s",
filenames->pass_filename, strerror(-rc));
return rc;
}
return 0;
}
/**
* Generate, Set or remove a dummy LUKS2 passphrase of a key.
*
* @param[in] keystore the key store
* @param[in] name the name of the key
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2. If NULKL, the passphrase is generated by
* random.
* @param[in] file_names the file names of the key
* @param[in] properties the properties of the key
* @param[in] prompt if true, prompt for change, if passphrase exists
* already
*
* @returns 0 on success, or a negative errno value on error
*/
static int _keystore_set_passphrase(struct keystore *keystore,
const char *name,
const char *passphrase_file,
const struct key_filenames *filenames,
struct properties *properties,
bool prompt)
{
char *volume_type;
int rc;
if (_keystore_passphrase_file_exists((struct key_filenames *)filenames)
&& prompt) {
warnx("There is already a LUKS2 dummy passphrase associated "
"with key '%s'.", name);
util_print_indented("To change a dummy passphrase of a key, "
"first remove the currently associated "
"passphrase with command 'zkey change "
"--name <key> --remove-dummy-passphrase' "
"and then set the new dummy passphrase for "
"the key.", 0);
return -EEXIST;
}
volume_type = _keystore_get_volume_type(properties);
if (volume_type == NULL) {
pr_verbose(keystore, "No volume type available");
return -EINVAL;
}
if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) != 0) {
warnx("The LUKS2 dummy passphrase can only be set for keys "
"with a volume type of LUKS2.");
free(volume_type);
return -EINVAL;
}
free(volume_type);
if (passphrase_file != NULL) {
rc = copy_file(passphrase_file, filenames->pass_filename, 0);
if (rc != 0) {
warnx("Failed to copy the passphrase phase '%s': %s",
passphrase_file, strerror(-rc));
return rc;
}
} else {
rc = copy_file("/dev/urandom", filenames->pass_filename,
DUMMY_PASSPHRASE_LEN);
if (rc != 0) {
warnx("Failed to generate the dummy passphrase: %s",
strerror(-rc));
return rc;
}
}
rc = _keystore_set_file_permission(keystore, filenames->pass_filename);
if (rc != 0)
return rc;
return 0;
}
/**
* Creates the key properties for a key
*
@@ -1615,6 +1760,8 @@ static int _keystore_set_default_properties(struct properties *key_props)
* @param[in] key_type the type of the key
* @param[in] kms the name of the KMS plugin, or NULL if no KMS is bound
* @param[out] props the properties object is allocated and returned
*
* @returns 0 on success, or a negative errno value on error
*/
static int _keystore_create_info_props(struct keystore *keystore,
const char *name,
@@ -1721,7 +1868,7 @@ out:
*
* @param[in] keystore the key store
* @param[in] name the name of the key
* @param[in] info_filename the file name of the key info file
* @param[in] filenames the file names of the key files
* @param[in] description textual description of the key (optional, can be NULL)
* @param[in] volumes a comma separated list of volumes associated with this
* key (optional, can be NULL)
@@ -1735,7 +1882,12 @@ out:
* default is used.
* @param[in] volume_type the type of volume
* @param[in] key_type the type of the key
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param[in] kms the name of the KMS plugin, or NULL if no KMS is bound
*
* @returns 0 on success, or a negative errno value on error
*/
static int _keystore_create_info_file(struct keystore *keystore,
const char *name,
@@ -1746,6 +1898,8 @@ static int _keystore_create_info_file(struct keystore *keystore,
size_t sector_size,
const char *volume_type,
const char *key_type,
bool gen_passphrase,
const char *passphrase_file,
const char *kms)
{
struct properties *key_props = NULL;
@@ -1758,12 +1912,24 @@ static int _keystore_create_info_file(struct keystore *keystore,
if (rc != 0)
return rc;
if (gen_passphrase || passphrase_file != NULL) {
rc = _keystore_set_passphrase(keystore, name, gen_passphrase ?
NULL : passphrase_file,
filenames, key_props, true);
if (rc != 0) {
pr_verbose(keystore, "Failed to set the passphrase: %s",
strerror(-rc));
goto out;
}
}
rc = _keystore_ensure_vp_exists(keystore, filenames, key_props);
if (rc != 0) {
warnx("Failed to generate the key verification pattern: %s",
strerror(-rc));
warnx("Make sure that kernel module 'paes_s390' is loaded and "
"that the 'paes' cipher is available");
remove(filenames->pass_filename);
goto out;
}
@@ -1772,12 +1938,14 @@ static int _keystore_create_info_file(struct keystore *keystore,
pr_verbose(keystore,
"Key info file '%s' could not be written: %s",
filenames->info_filename, strerror(-rc));
remove(filenames->pass_filename);
goto out;
}
rc = _keystore_set_file_permission(keystore, filenames->info_filename);
if (rc != 0) {
remove(filenames->info_filename);
remove(filenames->pass_filename);
goto out;
}
@@ -1809,6 +1977,9 @@ out:
* if NULL, the secure key is generated by random.
* @param[in] volume_type the type of volume
* @param[in] key_type the type of the key
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param[in] pkey_fd the file descriptor of /dev/pkey
*
* @returns 0 for success or a negative errno in case of an error
@@ -1818,9 +1989,10 @@ int keystore_generate_key(struct keystore *keystore, const char *name,
const char *apqns, bool noapqncheck,
size_t sector_size, size_t keybits, bool xts,
const char *clear_key_file, const char *volume_type,
const char *key_type, int pkey_fd)
const char *key_type, bool gen_passphrase,
const char *passphrase_file, int pkey_fd)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct properties *key_props = NULL;
char **apqn_list = NULL;
int rc;
@@ -1880,7 +2052,8 @@ int keystore_generate_key(struct keystore *keystore, const char *name,
rc = _keystore_create_info_file(keystore, name, &file_names,
description, volumes, apqns,
noapqncheck, sector_size, volume_type,
key_type, NULL);
key_type, gen_passphrase,
passphrase_file, NULL);
if (rc != 0)
goto out_free_props;
@@ -1921,6 +2094,9 @@ out_free_key_filenames:
* @param[in] xts if true, an XTS key is generated
* @param[in] volume_type the type of volume
* @param[in] key_type the type of the key (can be NULL)
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param[in] kms_options an array of KMS options specified, or NULL if no
* KMS options have been specified
* @param[in] num_kms_options the number of options in above array
@@ -1931,10 +2107,11 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
size_t sector_size, size_t keybits, bool xts,
const char *volume_type, const char *key_type,
bool gen_passphrase, const char *passphrase_file,
struct kms_option *kms_options,
size_t num_kms_options)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct properties *key_props = NULL;
struct kms_info *kms_info;
char *apqns = NULL;
@@ -2000,8 +2177,21 @@ int keystore_generate_key_kms(struct keystore *keystore, const char *name,
if (rc != 0)
goto out_free_key_filenames;
if (gen_passphrase || passphrase_file != NULL) {
rc = _keystore_set_passphrase(keystore, name, gen_passphrase ?
NULL : passphrase_file,
&file_names, key_props, true);
if (rc != 0) {
pr_verbose(keystore, "Failed to set the passphrase: %s",
strerror(-rc));
goto out_free_key_filenames;
}
}
rc = generate_kms_key(kms_info, name, key_type, key_props, xts,
keybits, file_names.skey_filename,
_keystore_passphrase_file_exists(&file_names) ?
file_names.pass_filename : NULL,
kms_options, num_kms_options, keystore->verbose);
if (rc != 0) {
warnx("KMS plugin '%s' failed to generate key '%s': %s",
@@ -2048,8 +2238,10 @@ out_del_info_file:
out_free_props:
if (key_props != NULL)
properties_free(key_props);
if (rc != 0)
if (rc != 0) {
remove(file_names.skey_filename);
remove(file_names.pass_filename);
}
out_free_key_filenames:
_keystore_free_key_filenames(&file_names);
if (apqns != NULL)
@@ -2081,6 +2273,9 @@ out_free_key_filenames:
* default is used.
* @param[in] import_file The name of a secure key containing the key to import
* @param[in] volume_type the type of volume
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param[in] lib the external library struct
*
* @returns 0 for success or a negative errno in case of an error
@@ -2089,9 +2284,10 @@ int keystore_import_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck, size_t sector_size,
const char *import_file, const char *volume_type,
bool gen_passphrase, const char *passphrase_file,
struct ext_lib *lib)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct properties *key_props = NULL;
size_t secure_key_size;
const char *key_type;
@@ -2206,7 +2402,8 @@ int keystore_import_key(struct keystore *keystore, const char *name,
rc = _keystore_create_info_file(keystore, name, &file_names,
description, volumes, apqns,
noapqncheck, sector_size, volume_type,
key_type, NULL);
key_type, gen_passphrase,
passphrase_file, NULL);
if (rc != 0)
goto out_free_props;
@@ -2256,23 +2453,33 @@ out_free_key_filenames:
* not be changed.
* @param[in] volume_type the type of volume. If NULL then the volume type is
* not changed.
* *
* @param[in] gen_passphrase if true, generate a (dummy) passphrase for LUKS2
* @param[in] passphrase_file the file name of a file containing a passphrase
* for LUKS2 (optional, can be NULL)
* @param[in] remove_passphrase if true, remove the (dummy) passphrase
* @param[in] quiet if true no confirmation prompt is shown when removing
* a (dummy) passphrase
*
* @returns 0 for success or a negative errno in case of an error
*
*/
int keystore_change_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck,
long int sector_size, const char *volume_type)
long int sector_size, const char *volume_type,
bool gen_passphrase, const char *passphrase_file,
bool remove_passphrase, bool quiet)
{
struct volume_check vol_check = { .keystore = keystore, .name = name,
.set = 0, .nocheck = 0 };
struct apqn_check apqn_check = { .noonlinecheck = noapqncheck,
.nomsg = 0 };
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct properties *key_props = NULL;
const char **passphrase_upd = NULL;
char *upd_volume_type = NULL;
char *apqns_prop, *key_type;
const char *null_ptr = NULL;
char *upd_volumes = NULL;
size_t secure_key_size;
u8 mkvp[MKVP_LENGTH];
@@ -2401,6 +2608,38 @@ int keystore_change_key(struct keystore *keystore, const char *name,
upd_volume_type = properties_get(key_props,
PROP_NAME_VOLUME_TYPE);
/* Remove dummy passphrase if change to PLAIN volume type */
if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) != 0 &&
_keystore_passphrase_file_exists(&file_names)) {
rc = _keystore_remove_passphrase(keystore, name,
&file_names, key_props,
false);
if (rc != 0)
goto out;
passphrase_upd = &null_ptr;
}
}
if (gen_passphrase || passphrase_file != NULL) {
rc = _keystore_set_passphrase(keystore, name, gen_passphrase ?
NULL : passphrase_file,
&file_names, key_props, true);
if (rc != 0)
goto out;
passphrase_upd = (const char **)&file_names.pass_filename;
}
if (remove_passphrase) {
if (_keystore_passphrase_file_exists(&file_names))
passphrase_upd = &null_ptr;
rc = _keystore_remove_passphrase(keystore, name, &file_names,
key_props, !quiet);
if (rc != 0)
goto out;
}
if (kms_bound) {
@@ -2412,7 +2651,7 @@ int keystore_change_key(struct keystore *keystore, const char *name,
description, upd_volumes,
upd_volume_type, sector_size >= 0 ?
sect_size : NULL,
keystore->verbose);
passphrase_upd, keystore->verbose);
if (rc != 0) {
warnx("KMS plugin '%s' failed to set key properties "
"for key '%s': %s",
@@ -2441,6 +2680,8 @@ int keystore_change_key(struct keystore *keystore, const char *name,
pr_verbose(keystore, "Successfully changed key '%s'", name);
out:
if (rc != 0 && passphrase_upd != NULL && *passphrase_upd != NULL)
remove(*passphrase_upd);
_keystore_free_key_filenames(&file_names);
if (key_props != NULL)
properties_free(key_props);
@@ -2467,10 +2708,11 @@ out:
int keystore_rename_key(struct keystore *keystore, const char *name,
const char *newname)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames new_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct key_filenames new_names = { 0 };
struct properties *key_props = NULL;
bool reenc_exists = false;
bool pass_exists = false;
char *msg;
int rc;
@@ -2516,6 +2758,16 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
goto out_rename_info;
}
}
if (_keystore_passphrase_file_exists(&file_names)) {
pass_exists = true;
if (rename(file_names.pass_filename,
new_names.pass_filename) != 0) {
rc = -errno;
pr_verbose(keystore, "Failed to rename '%s': %s",
file_names.pass_filename, strerror(-rc));
goto out_rename_info;
}
}
key_props = properties_new();
rc = properties_load(key_props, new_names.info_filename, 1);
@@ -2531,7 +2783,7 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
rc = set_kms_key_properties(keystore->kms_info, key_props,
newname, NULL, NULL, NULL, NULL,
keystore->verbose);
NULL, keystore->verbose);
if (rc != 0) {
warnx("KMS plugin '%s' failed to set key properties "
"for key '%s': %s",
@@ -2549,6 +2801,16 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
_keystore_msg_for_volumes(msg, key_props, VOLUME_TYPE_PLAIN);
free(msg);
if (_keystore_passphrase_file_exists(&new_names)) {
util_asprintf(&msg, "The following volumes are associated with "
"the renamed key '%s'. You should adjust the "
"corresponding crypttab entries to use the new "
"dummy passphrase file name '%s'.", newname,
new_names.pass_filename);
_keystore_msg_for_volumes(msg, key_props, VOLUME_TYPE_LUKS2);
free(msg);
}
pr_verbose(keystore, "Successfully renamed key '%s' to '%s'", name,
newname);
@@ -2557,6 +2819,8 @@ int keystore_rename_key(struct keystore *keystore, const char *name,
out_rename_info:
if (reenc_exists)
rename(file_names.renc_filename, new_names.renc_filename);
if (pass_exists)
rename(file_names.pass_filename, new_names.pass_filename);
rename(new_names.info_filename, file_names.info_filename);
out_rename_skey:
@@ -2613,6 +2877,8 @@ static struct util_rec *_keystore_setup_record(bool validation)
util_rec_def(rec, REC_KMS, UTIL_REC_ALIGN_LEFT, 54, REC_KMS);
util_rec_def(rec, REC_KMS_KEY_LABEL, UTIL_REC_ALIGN_LEFT, 54,
REC_KMS_KEY_LABEL);
util_rec_def(rec, REC_PASSPHRASE_FILE, UTIL_REC_ALIGN_LEFT, 54,
REC_PASSPHRASE_FILE);
util_rec_def(rec, REC_CREATION_TIME, UTIL_REC_ALIGN_LEFT, 54,
REC_CREATION_TIME);
util_rec_def(rec, REC_CHANGE_TIME, UTIL_REC_ALIGN_LEFT, 54,
@@ -2629,7 +2895,8 @@ static void _keystore_print_record(struct util_rec *rec,
bool validation, const char *skey_filename,
size_t secure_key_size, bool is_xts,
size_t clear_key_bitsize, bool valid,
bool is_old_mk, bool reenc_pending, u8 *mkvp)
bool is_old_mk, bool reenc_pending, u8 *mkvp,
const char *pass_filename)
{
char temp_vp[VERIFICATION_PATTERN_LEN + 2];
char *kms_xts_key1_label = NULL;
@@ -2767,6 +3034,10 @@ static void _keystore_print_record(struct util_rec *rec,
label_argz_len);
else
util_rec_set(rec, REC_KMS_KEY_LABEL, "(local)");
if (pass_filename != NULL)
util_rec_set(rec, REC_PASSPHRASE_FILE, pass_filename);
else
util_rec_set(rec, REC_PASSPHRASE_FILE, "(none)");
util_rec_set(rec, REC_CREATION_TIME, creation);
util_rec_set(rec, REC_CHANGE_TIME,
change != NULL ? change : "(never)");
@@ -2966,7 +3237,9 @@ static int _keystore_process_validate(struct keystore *keystore,
is_xts_key(secure_key, secure_key_size),
clear_key_bitsize, valid, is_old_mk,
_keystore_reencipher_key_exists(file_names),
mkvp);
mkvp,
_keystore_passphrase_file_exists(file_names) ?
file_names->pass_filename : NULL);
if (valid && is_old_mk) {
util_print_indented("WARNING: The secure key is currently "
@@ -3434,8 +3707,8 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
{
struct volume_check vol_check = { .keystore = keystore, .name = newname,
.set = 0, .nocheck = 0 };
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames new_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct key_filenames new_names = { 0 };
struct properties *key_prop = NULL;
size_t secure_key_size;
bool kms_bound = false;
@@ -3536,7 +3809,6 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
pr_verbose(keystore,
"Key info file '%s' could not be written: %s",
new_names.info_filename, strerror(-rc));
remove(new_names.skey_filename);
goto out;
}
@@ -3544,6 +3816,23 @@ int keystore_copy_key(struct keystore *keystore, const char *name,
if (rc != 0)
goto out;
if (_keystore_passphrase_file_exists(&file_names)) {
rc = copy_file(file_names.skey_filename,
new_names.pass_filename, 0);
if (rc != 0) {
pr_verbose(keystore,
"Passphrase file '%s' could not be copied: "
"%s", new_names.pass_filename,
strerror(-rc));
goto out;
}
rc = _keystore_set_file_permission(keystore,
file_names.pass_filename);
if (rc != 0)
goto out;
}
pr_verbose(keystore, "Successfully copied key '%s' to '%s'", name,
newname);
@@ -3551,6 +3840,7 @@ out:
if (rc != 0) {
remove(new_names.skey_filename);
remove(new_names.info_filename);
remove(new_names.pass_filename);
}
_keystore_free_key_filenames(&file_names);
@@ -3576,7 +3866,7 @@ out:
int keystore_export_key(struct keystore *keystore, const char *name,
const char *export_file)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
size_t secure_key_size;
u8 *secure_key;
int rc;
@@ -3675,7 +3965,7 @@ int keystore_remove_key(struct keystore *keystore, const char *name,
bool quiet, struct kms_option *kms_options,
size_t num_kms_options)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
struct properties *key_props = NULL;
int rc;
@@ -3739,6 +4029,13 @@ int keystore_remove_key(struct keystore *keystore, const char *name,
file_names.renc_filename, strerror(-rc));
}
}
if (_keystore_passphrase_file_exists(&file_names)) {
if (remove(file_names.pass_filename) != 0) {
rc = -errno;
pr_verbose(keystore, "Failed to remove '%s': %s",
file_names.pass_filename, strerror(-rc));
}
}
pr_verbose(keystore, "Successfully removed key '%s'", name);
out:
@@ -3794,7 +4091,9 @@ static int _keystore_display_key(struct keystore *keystore,
is_xts_key(secure_key, secure_key_size),
clear_key_bitsize, 0, 0,
_keystore_reencipher_key_exists(file_names),
NULL);
NULL,
_keystore_passphrase_file_exists(file_names) ?
file_names->pass_filename : NULL);
out:
free(secure_key);
@@ -3910,6 +4209,7 @@ struct crypt_info {
size_t key_file_size,
size_t sector_size,
const char *volume_type,
const char *passphrase_file,
struct crypt_info *info);
};
@@ -3925,6 +4225,7 @@ struct crypt_info {
* @param[in] key_file_size the size of the key file in bytes
* @param[in] sector_size the sector size in bytes or 0 if not specified
* @param[in] volume_type the volume type
* @param[in] passphrase_file the passphrase file name (can be NULL)
* @param[in] info processing info
*
* @returns 0 if successful, a negative errno value otherwise
@@ -3937,6 +4238,7 @@ static int _keystore_process_cryptsetup(struct keystore *keystore,
size_t key_file_size,
size_t sector_size,
const char *volume_type,
const char *passphrase_file,
struct crypt_info *info)
{
char *keyfile_opt = NULL, *offset_opt = NULL;
@@ -3957,6 +4259,9 @@ static int _keystore_process_cryptsetup(struct keystore *keystore,
if (info->keyfile_size > 0)
util_asprintf(&size_opt, "--keyfile-size %lu ",
info->keyfile_size);
} else if (passphrase_file != NULL) {
util_asprintf(&keyfile_opt, "--key-file '%s' ",
passphrase_file);
}
if (info->tries > 0)
util_asprintf(&tries_opt, "--tries %lu ", info->tries);
@@ -4069,6 +4374,7 @@ static int _keystore_process_cryptsetup(struct keystore *keystore,
* @param[in] key_file_size the size of the key file in bytes
* @param[in] sector_size the sector size in bytes or 0 if not specified
* @param[in] volume_type the volume type
* @param[in] passphrase_file the passphrase file name (can be NULL)
* @param[in] info processing info (not used here)
*
* @returns 0 if successful, a negative errno value otherwise
@@ -4082,37 +4388,30 @@ static int _keystore_process_crypttab(struct keystore *UNUSED(keystore),
size_t key_file_size,
size_t sector_size,
const char *volume_type,
const char *passphrase_file,
struct crypt_info *info)
{
char temp[1000];
if (strcasecmp(volume_type, VOLUME_TYPE_PLAIN) == 0) {
if (sector_size > 0) {
sprintf(temp,
"WARNING: volume '%s' is using a sector size "
"of %lu. At the time this utility was "
"developed, systemd's support of crypttab did "
"not support to specify a sector size with "
"plain dm-crypt devices. The generated "
"crypttab entry might or might not work, and "
"might need manual adoptions.", volume,
sector_size);
util_print_indented(temp, 0);
}
sprintf(temp, ",sector-size=%lu", sector_size);
printf("%s\t%s\t%s\tplain,cipher=%s,size=%lu%s\n",
dmname, volume, key_file_name, cipher_spec,
key_file_size * 8, sector_size > 0 ? temp : "");
} else if (strcasecmp(volume_type, VOLUME_TYPE_LUKS2) == 0) {
printf("%s\t%s\t%s\tluks", dmname, volume,
info->keyfile != NULL ? info->keyfile : "none");
if (info->keyfile != NULL) {
printf("%s\t%s\t%s\tluks", dmname, volume,
info->keyfile);
if (info->keyfile_offset > 0)
printf(",keyfile-offset=%lu",
info->keyfile_offset);
if (info->keyfile_size > 0)
printf(",keyfile-size=%lu", info->keyfile_size);
} else if (passphrase_file != NULL) {
printf("%s\t%s\t%s\tluks", dmname, volume,
passphrase_file);
} else {
printf("%s\t%s\tnone\tluks", dmname, volume);
}
if (info->tries > 0)
printf(",tries=%lu", info->tries);
@@ -4237,7 +4536,10 @@ static int _keystore_process_crypt(struct keystore *keystore,
rc = info->process_func(keystore, vol, dmname,
cipher_spec, file_names->skey_filename,
secure_key_size, sector_size,
volume_type, info);
volume_type,
_keystore_passphrase_file_exists(file_names) ?
file_names->pass_filename : NULL,
info);
if (rc != 0)
break;
}
@@ -4403,7 +4705,7 @@ int keystore_convert_key(struct keystore *keystore, const char *name,
const char *key_type, bool noapqncheck, bool quiet,
int pkey_fd, struct ext_lib *lib)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct key_filenames file_names = { 0 };
u8 output_key[2 * MAX_SECURE_KEY_SIZE];
struct properties *properties = NULL;
int rc, min_level, selected = 1;
@@ -4920,6 +5222,7 @@ struct kms_import {
* @param[in] volumes the associated volumes of the key (can be NULL)
* @param[in] volume_type the volume type of the volume (can be NULL)
* @param[in] sector_size the sector size of the volume (0 means default)
* @param[in] passphrase the passphrase of the key (can be NULL)
* @param[in] addl_info_argz an argz string containing additional KMS plugin
* specific infos to be displayed, or NULL if none.
* @param[in] addl_info_len length of the argz string in addl_info_argz
@@ -4940,12 +5243,13 @@ static int _keystore_process_kms_import(const char *key1_id,
const char *volumes,
const char *volume_type,
size_t sector_size,
const char *passphrase,
const char *UNUSED(addl_info_argz),
size_t UNUSED(addl_info_len),
void *private_data)
{
struct key_filenames file_names = { NULL, NULL, NULL };
struct kms_import *import_data = private_data;
struct key_filenames file_names = { 0 };
u8 secure_key[2 * MAX_SECURE_KEY_SIZE];
struct properties *key_props = NULL;
char vp[VERIFICATION_PATTERN_LEN];
@@ -5042,6 +5346,23 @@ prompt_alt_name:
if (rc != 0)
goto out;
if (passphrase != NULL && volume_type != NULL &&
strcasecmp(volume_type, VOLUME_TYPE_LUKS2) == 0) {
rc = store_passphrase_from_base64(passphrase,
file_names.pass_filename,
keystore->verbose);
if (rc != 0) {
pr_verbose(keystore, "Failed to parse passphrase: %s",
strerror(-rc));
goto out;
}
rc = _keystore_set_file_permission(keystore,
file_names.pass_filename);
if (rc != 0)
goto out_remove;
}
rc = properties_set(key_props, xts ? PROP_NAME_KMS_XTS_KEY1_ID :
PROP_NAME_KMS_KEY_ID, key1_id);
if (rc != 0) {
@@ -5267,7 +5588,9 @@ static int _keystore_refresh_kms_key(struct keystore *keystore,
rc = refresh_kms_key(keystore->kms_info, properties,
&description, &cipher, &iv_mode, &volumes,
&volume_type, &sector_size,
file_names->skey_filename, keystore->verbose);
file_names->skey_filename,
file_names->pass_filename,
keystore->verbose);
if (rc != 0) {
warnx("KMS plugin '%s' failed to refresh key '%s': %s",
keystore->kms_info->plugin_name, name, strerror(-rc));
@@ -5277,6 +5600,17 @@ static int _keystore_refresh_kms_key(struct keystore *keystore,
goto out;
}
rc = _keystore_set_file_permission(keystore, file_names->skey_filename);
if (rc != 0)
goto out;
if (_keystore_passphrase_file_exists(file_names)) {
rc = _keystore_set_file_permission(keystore,
file_names->pass_filename);
if (rc != 0)
goto out;
}
if (!refresh_data->refresh_properties)
goto save_props;
@@ -5345,6 +5679,10 @@ save_props:
goto out;
}
rc = _keystore_set_file_permission(keystore, file_names->info_filename);
if (rc != 0)
goto out;
out:
if (rc == 0) {
printf("Successfully refreshed key '%s'\n", name);

View File

@@ -54,12 +54,14 @@ int keystore_generate_key(struct keystore *keystore, const char *name,
const char *apqns, bool noapqncheck,
size_t sector_size, size_t keybits, bool xts,
const char *clear_key_file, const char *volume_type,
const char *key_type, int pkey_fd);
const char *key_type, bool gen_passphrase,
const char *passphrase_file, int pkey_fd);
int keystore_generate_key_kms(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
size_t sector_size, size_t keybits, bool xts,
const char *volume_type, const char *key_type,
bool gen_passphrase, const char *passphrase_file,
struct kms_option *kms_options,
size_t num_kms_options);
@@ -67,12 +69,15 @@ int keystore_import_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck, size_t sector_size,
const char *import_file, const char *volume_type,
bool gen_passphrase, const char *passphrase_file,
struct ext_lib *lib);
int keystore_change_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, bool noapqncheck,
long int sector_size, const char *volume_type);
long int sector_size, const char *volume_type,
bool gen_passphrase, const char *passphrase_file,
bool remove_passphrase, bool quiet);
int keystore_rename_key(struct keystore *keystore, const char *name,
const char *newname);

View File

@@ -40,14 +40,16 @@
#define ENVVAR_ZKEY_KMS_PLUGINS "ZKEY_KMS_PLUGINS"
#define DEFAULT_KMS_PLUGINS "/etc/zkey/kms-plugins.conf"
#define KMS_PLUGIN_LOCATION "/usr/lib64/zkey"
#ifndef KMS_PLUGIN_LOCATION
#error KMS_PLUGIN_LOCATION must be defined
#endif
#define KMS_CONFIG_FILE "kms.conf"
#define KMS_CONFIG_PROP_KMS "kms"
#define KMS_CONFIG_PROP_KMS_CONFIG "config"
#define KMS_CONFIG_PROP_APQNS "apqns"
#define KMS_CONFIG_PROP_CCA_APQNS "ep11_apqns"
#define KMS_CONFIG_PROP_EP11_APQNS "cca_apqns"
#define KMS_CONFIG_PROP_CCA_APQNS "cca_apqns"
#define KMS_CONFIG_PROP_EP11_APQNS "ep11_apqns"
#define KMS_CONFIG_LOCAL "local"
#define KMS_KEY_PROP_NAME "zkey-name"
@@ -62,6 +64,7 @@
#define KMS_KEY_PROP_XTS_KEY2_ID "xts-key2-id"
#define KMS_KEY_PROP_XTS_KEY1_LABEL "xts-key1-label"
#define KMS_KEY_PROP_XTS_KEY2_LABEL "xts-key2-label"
#define KMS_KEY_PROP_PASSPHRASE "dummy-passphrase-base64"
#define KMS_REC_LABEL "Key label"
#define KMS_REC_NAME "Name"
@@ -2118,6 +2121,8 @@ static char *_get_system_specific_prop_name(const char *prop_name)
* @param[in] keybits the key bit size (e.g. 128, 196, 256, 0 to use the
* plugin's default)
* @param[in] filename the file name to store the key in
* @param[in] passphrase_file the file name containing the LUKS2 passphrase,
* or NULL if no passphrase is set
* @param[in] kms_options an array of KMS options specified, or NULL if no
* KMS options have been specified
* @param[in] num_kms_options the number of options in above array
@@ -2129,6 +2134,7 @@ static char *_get_system_specific_prop_name(const char *prop_name)
int generate_kms_key(struct kms_info *kms_info, const char *name,
const char *key_type, struct properties *key_props,
bool xts, size_t keybits, const char *filename,
const char *passphrase_file,
struct kms_option *kms_options, size_t num_kms_options,
bool verbose)
{
@@ -2138,12 +2144,13 @@ int generate_kms_key(struct kms_info *kms_info, const char *name,
char key2_label[KMS_KEY_LABEL_SIZE + 1] = { 0 };
char key1_id[KMS_KEY_ID_SIZE + 1] = { 0 };
char key2_id[KMS_KEY_ID_SIZE + 1] = { 0 };
struct kms_property kms_props[12];
struct kms_property kms_props[13];
int xts_mode_prop = -1, rc = 0;
size_t key_size, key_blob_size;
enum kms_key_mode key_mode;
size_t num_kms_props = 0;
char *sys_volumes = NULL;
char *passphrase = NULL;
util_assert(kms_info != NULL, "Internal error: kms_info is NULL");
util_assert(name != NULL, "Internal error: name is NULL");
@@ -2207,6 +2214,19 @@ int generate_kms_key(struct kms_info *kms_info, const char *name,
"XTS-KEY-1");
}
if (passphrase_file != NULL) {
passphrase = read_passphrase_as_base64(passphrase_file,
verbose);
if (passphrase == NULL) {
pr_verbose(verbose, "Failed to read passphrase from "
"file '%s'", passphrase_file);
goto out;
}
ADD_KMS_PROPS(kms_props, num_kms_props, KMS_KEY_PROP_PASSPHRASE,
passphrase);
}
key_mode = xts ? KMS_KEY_MODE_XTS_1 : KMS_KEY_MODE_NON_XTS;
key_blob_size = key_size;
@@ -2331,6 +2351,8 @@ out:
free(sector_size);
if (sys_volumes != NULL)
free(sys_volumes);
if (passphrase != NULL)
free(passphrase);
return rc;
}
@@ -2346,20 +2368,28 @@ out:
* @param[in] volumes the volumes of the key (can be NULL)
* @param[in] vol_type the volume type of the key (can be NULL)
* @param[in] sector_size the sector_size of the key (can be NULL)
* @param[in] passphrase_file an address to a character string containing the
* file name containing the LUKS2 passphrase,
* or NULL if no passphrase is set. If
* passphrase_file itself is NULL, then no change in
* the passphrase property.
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 for success or a negative errno in case of an error.
*/
int set_kms_key_properties(struct kms_info *kms_info,
struct properties *key_props,
const char *name, const char *description,
const char *volumes, const char *vol_type,
const char *sector_size, bool verbose)
const char *sector_size,
const char **passphrase_file,
bool verbose)
{
char *key1_id = NULL, *key2_id = NULL;
struct kms_property kms_props[10];
struct kms_property kms_props[11];
size_t num_kms_props = 0;
char *sys_volumes = NULL;
char *passphrase = NULL;
char *sys_name = NULL;
bool xts = false;
@@ -2414,6 +2444,22 @@ int set_kms_key_properties(struct kms_info *kms_info,
if (sector_size != NULL)
ADD_KMS_PROPS(kms_props, num_kms_props,
KMS_KEY_PROP_SECTOR_SIZE, sector_size);
if (passphrase_file != NULL) {
/* *passphrase_file is NULL to remove the propoerty */
if (*passphrase_file != NULL) {
passphrase =
read_passphrase_as_base64(*passphrase_file,
verbose);
if (passphrase == NULL) {
pr_verbose(verbose, "Failed to read passphrase"
" from file '%s'", *passphrase_file);
goto out;
}
}
ADD_KMS_PROPS(kms_props, num_kms_props,
KMS_KEY_PROP_PASSPHRASE, passphrase);
}
if (num_kms_props == 0)
goto out;
@@ -2448,6 +2494,8 @@ out:
free(key1_id);
if (key2_id != NULL)
free(key2_id);
if (passphrase != NULL)
free(passphrase);
return rc;
}
@@ -2640,6 +2688,7 @@ static int _process_kms_keys_cb(const char *key_id, const char *key_label,
const char *name, *volumes, *cipher, *iv_mode, *description;
const char *xts_key2_id = NULL, *xts_key2_label = NULL;
const char *xts_key, *volume_type, *temp;
const char *passphrase;
size_t sector_size = 0;
bool xts = false;
@@ -2695,6 +2744,8 @@ static int _process_kms_keys_cb(const char *key_id, const char *key_label,
KMS_KEY_PROP_SECTOR_SIZE);
if (temp != NULL)
sscanf(temp, "%lu", &sector_size);
passphrase = _find_property(properties, num_properties,
KMS_KEY_PROP_PASSPHRASE);
if (process_data->label_filter != NULL) {
if (fnmatch(process_data->label_filter, key_label,
@@ -2728,6 +2779,7 @@ static int _process_kms_keys_cb(const char *key_id, const char *key_label,
xts ? key_bits * 2 : key_bits,
description, cipher, iv_mode,
volumes, volume_type, sector_size,
passphrase,
addl_info_argz, addl_info_len,
process_data->private_data);
}
@@ -2865,6 +2917,7 @@ static int _list_kms_keys_cb(const char *UNUSED(key1_id),
const char *UNUSED(cipher),
const char *UNUSED(iv_mode), const char *volumes,
const char *volume_type, size_t sector_size,
const char *UNUSED(passphrase),
const char *addl_info_argz, size_t addl_info_len,
void *private_data)
{
@@ -3139,6 +3192,7 @@ out:
* @param[out] volume_type on return: the volume_type property
* @param[out] sector_size on return: the sector_size property
* @param[in] filename the file name to store the refreshed key blob in
* @param[in] passphrase_file the file name to store the dummy passphras in
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 for success or a negative errno in case of an error.
@@ -3146,7 +3200,8 @@ out:
int refresh_kms_key(struct kms_info *kms_info, struct properties *key_props,
char **description, char **cipher, char **iv_mode,
char **volumes, char **volume_type, ssize_t *sector_size,
const char *filename, bool verbose)
const char *filename, const char *passphrase_file,
bool verbose)
{
struct kms_property *properties = NULL;
u8 key_blob[2 * MAX_SECURE_KEY_SIZE];
@@ -3239,6 +3294,29 @@ int refresh_kms_key(struct kms_info *kms_info, struct properties *key_props,
if (str != NULL)
sscanf(str, "%lu", (long unsigned int *)sector_size);
}
if (passphrase_file != NULL && volume_type != NULL &&
*volume_type != NULL && strcasecmp(*volume_type, "luks2") == 0) {
str = _find_property(properties, num_properties,
KMS_KEY_PROP_PASSPHRASE);
if (str != NULL) {
rc = store_passphrase_from_base64(str, passphrase_file,
verbose);
if (rc != 0) {
pr_verbose(verbose,
"Failed to parse passphrase: %s",
strerror(-rc));
goto out;
}
} else {
rc = remove(passphrase_file);
if (rc != 0 && errno != ENOENT) {
pr_verbose(verbose,
"Failed to remove passphrase_file: "
"%s", strerror(errno));
goto out;
}
}
}
key_blob_size = sizeof(key_blob);
memset(key_blob, 0, key_blob_size);

View File

@@ -74,6 +74,7 @@ int get_kms_apqns_for_key_type(struct kms_info *kms_info, const char *key_type,
int generate_kms_key(struct kms_info *kms_info, const char *name,
const char *key_type, struct properties *key_props,
bool xts, size_t keybits, const char *filename,
const char *passphrase_file,
struct kms_option *kms_options, size_t num_kms_options,
bool verbose);
@@ -81,7 +82,9 @@ int set_kms_key_properties(struct kms_info *kms_info,
struct properties *key_props,
const char *name, const char *description,
const char *volumes, const char *vol_type,
const char *sector_size, bool verbose);
const char *sector_size,
const char **passphrase_file,
bool verbose);
int remove_kms_key(struct kms_info *kms_info, struct properties *key_props,
struct kms_option *kms_options, size_t num_kms_options,
@@ -94,6 +97,7 @@ typedef int (*kms_process_callback)(const char *key1_id, const char *key1_label,
const char *description, const char *cipher,
const char *iv_mode, const char *volumes,
const char *volume_type, size_t sector_size,
const char *passphrase,
const char *addl_info_argz,
size_t addl_info_len,
void *private_data);
@@ -118,6 +122,7 @@ int import_kms_key(struct kms_info *kms_info, const char *key1_id,
int refresh_kms_key(struct kms_info *kms_info, struct properties *key_props,
char **description, char **cipher, char **iv_mode,
char **volumes, char **volume_type, ssize_t *sector_size,
const char *filename, bool verbose);
const char *filename, const char *passphrase_file,
bool verbose);
#endif

View File

@@ -1337,7 +1337,7 @@ int validate_secure_key(int pkey_fd,
int generate_key_verification_pattern(const u8 *key, size_t key_size,
char *vp, size_t vp_len, bool verbose)
{
int tfmfd = -1, opfd = -1, rc = 0;
int tfmfd = -1, opfd = -1, rc = 0, retry_count = 0;
char null_msg[ENC_ZERO_LEN];
char enc_zero[ENC_ZERO_LEN];
struct af_alg_iv *alg_iv;
@@ -1385,12 +1385,30 @@ int generate_key_verification_pattern(const u8 *key, size_t key_size,
goto out;
}
retry_setkey:
if (setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY, key,
key_size) < 0) {
rc = -errno;
pr_verbose(verbose, "Failed to set the key");
pr_verbose(verbose, "Failed to set the key: %s",
strerror(-rc));
/*
* After a master key change, it can happen that the setkey
* operation returns EINVAL or EAGAIN, although the key is
* valid. This is a temporary situation and the operation will
* succeed, once the firmware has completed some internal
* processing related with the master key change.
* Delay 1 second and retry up to 10 times.
*/
if ((rc == -EINVAL || rc == -EAGAIN) && retry_count < 10) {
pr_verbose(verbose, "Retrying after 1 second...");
retry_count++;
sleep(1);
goto retry_setkey;
}
goto out;
}
rc = 0;
opfd = accept(tfmfd, NULL, NULL);
if (opfd < 0) {

View File

@@ -15,6 +15,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
@@ -25,7 +26,8 @@
#include "lib/util_rec.h"
#include "lib/util_base.h"
#include <openssl/crypto.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include "utils.h"
#include "properties.h"
@@ -1128,6 +1130,7 @@ bool prompt_for_yes(bool verbose)
{
char str[20];
fflush(stdout);
if (fgets(str, sizeof(str), stdin) == NULL)
return false;
@@ -1174,3 +1177,199 @@ char *printable_mkvp(enum card_type cardtype, u8 *mkvp)
return mkvp_print_buf;
}
/*
* Copy the contents of one file into another file. If num_bytes is zero,
* then all content until EOF of the input file is copied. Otherwise only up to
* num_bytes is copied.
*
* @param[in] in_file_name the file name of the input file
* @param[in] out_file_name the file name of the output file
* @param[in] num_bytes the number of bytes to copy, or 0 to copy until
* EOF of the input file
*
* @returns zero for success, or a negative error in case of an error
*/
int copy_file(const char *in_file_name, const char *out_file_name,
size_t num_bytes)
{
FILE *fp_in = NULL, *fp_out = NULL;
size_t num = 0, len;
char buff[1024];
int rc = 0;
fp_in = fopen(in_file_name, "r");
if (fp_in == NULL) {
rc = -errno;
warnx("Failed to open '%s': %s", in_file_name, strerror(-rc));
goto out;
}
fp_out = fopen(out_file_name, "w");
if (fp_out == NULL) {
rc = -errno;
warnx("Failed to open '%s': %s", out_file_name, strerror(-rc));
goto out;
}
while (!feof(fp_in) && (num_bytes == 0 || num < num_bytes)) {
len = fread(buff, 1, num_bytes == 0 ? sizeof(buff) :
MIN(num_bytes - num, sizeof(buff)), fp_in);
if (ferror(fp_in)) {
rc = -EIO;
warnx("Failed to read from '%s': %s", in_file_name,
strerror(-rc));
break;
}
if (len == 0)
break;
if (fwrite(buff, len, 1, fp_out) != 1) {
rc = -errno;
warnx("Failed to write to '%s': %s", out_file_name,
strerror(-rc));
break;
}
num += len;
}
out:
if (fp_in != NULL)
fclose(fp_in);
if (fp_out != NULL)
fclose(fp_out);
return rc;
}
/**
* Reads the passphrase from the specified file and returns the passphrase as
* an base64 encoded string. The returned string must be freed by the caller.
*
* @param[in] filename the file name of the file containing the passphrase
* @param[in] verbose if true, additional error messages are printed.
*
* @returns an allocated string
*/
char *read_passphrase_as_base64(const char *filename, bool verbose)
{
unsigned char *ret = NULL, *buf = NULL;
int outlen, len;
struct stat sb;
FILE *fp;
if (stat(filename, &sb) != 0) {
pr_verbose(verbose, "stat on file '%s' failed: %s", filename,
strerror(errno));
return NULL;
}
if (sb.st_size == 0) {
pr_verbose(verbose, "File '%s' is empty", filename);
return NULL;
}
fp = fopen(filename, "r");
if (fp == NULL) {
pr_verbose(verbose, "Open of file '%s' failed: %s", filename,
strerror(errno));
return NULL;
}
buf = malloc(sb.st_size);
if (buf == NULL) {
pr_verbose(verbose, "Malloc failed");
goto out;
}
if (fread(buf, sb.st_size, 1, fp) != 1) {
pr_verbose(verbose, "Reading file '%s' failed: %s", filename,
strerror(errno));
goto out;
}
outlen = (sb.st_size / 3) * 4;
if (sb.st_size % 3 > 0)
outlen += 4;
ret = malloc(outlen + 1);
if (ret == NULL) {
pr_verbose(verbose, "Malloc failed");
goto out;
}
len = EVP_EncodeBlock(ret, buf, sb.st_size);
if (len != outlen) {
pr_verbose(verbose, "EVP_EncodeBlock failed");
free(ret);
ret = NULL;
goto out;
}
ret[outlen] = '\0';
out:
free(buf);
fclose(fp);
return (char *)ret;
}
/**
* Stores the passphrase into the specified file. Decodes the base64 string into
* bytes.
*
* @param[in] b64_string the passphrase as a base64 string
* @param[in] filename the file name of the file containing the passphrase
* @param[in] verbose if true, additional error messages are printed.
*
* @returns 0 for success or a negative errno in case of an error.
*/
int store_passphrase_from_base64(const char *b64_string, const char *filename,
bool verbose)
{
size_t len, outlen, rawlen, i;
unsigned char *buf;
FILE *fp = NULL;
int rc = 0;
len = strlen(b64_string);
rawlen = outlen = (len / 4) * 3;
for (i = len - 1; b64_string[i] == '='; i--, rawlen--)
;
buf = malloc(outlen);
if (buf == NULL) {
pr_verbose(verbose, "Malloc failed");
return -ENOMEM;
}
fp = fopen(filename, "w");
if (fp == NULL) {
pr_verbose(verbose, "Open of file '%s' failed: %s", filename,
strerror(errno));
rc = -EIO;
goto out;
}
len = EVP_DecodeBlock(buf, (unsigned char *)b64_string, len);
if (len != outlen) {
pr_verbose(verbose, "EVP_DecodeBlock failed");
goto out;
}
if (fwrite(buf, rawlen, 1, fp) != 1) {
pr_verbose(verbose, "Writing file '%s' failed: %s", filename,
strerror(errno));
goto out;
}
out:
if (fp != NULL)
fclose(fp);
free(buf);
return rc;
}

View File

@@ -77,4 +77,11 @@ bool prompt_for_yes(bool verbose);
char *printable_mkvp(enum card_type cardtype, u8 *mkvp);
int copy_file(const char *in_file_name, const char *out_file_name,
size_t num_bytes);
char *read_passphrase_as_base64(const char *filename, bool verbose);
int store_passphrase_from_base64(const char *hex_string, const char *filename,
bool verbose);
#endif

View File

@@ -126,6 +126,9 @@ key repository.
.RB [ \-\-key-type | \-K
.IR type ]
.RB [ \-\-local | \-L ]
.RB [ \-\-gen\-dummy\-passphrase ]
.RB [ \-\-set\-dummy\-passphrase
.IR passphrase\-file ]
.RB [ KMS\-plugin\ specific\ options ]
.RB [ \-\-verbose | \-V ]
.PP
@@ -379,6 +382,9 @@ EP11-AES to be installed. For the supported environments and downloads, see:
.IR bytes ]
.RB [ \-\-volume-type | \-t
.IR type ]
.RB [ \-\-gen\-dummy\-passphrase ]
.RB [ \-\-set\-dummy\-passphrase
.IR passphrase\-file ]
.RB [ \-\-verbose | \-V ]
.
.PP
@@ -515,6 +521,11 @@ because the secure key is contained in the LUKS2 header.
.IR bytes ]
.RB [ \-\-volume-type | \-t
.IR type ]
.RB [ \-\-gen\-dummy\-passphrase ]
.RB [ \-\-set\-dummy\-passphrase
.IR passphrase\-file ]
.RB [ \-\-remove\-dummy\-passphrase ]
.RB [ \-\-force | \-F ]
.RB [ \-\-verbose | \-V ]
.
.PP
@@ -661,7 +672,7 @@ option to generate crypttab entries for the specified volume type only.
For LUKS2 volumes, a passphrase is required. You are prompted for the
passphrase during system startup when crypttab is evaluated, unless option
.B \-\-key\-file
is specified. Option
is specified, or a dummy passphrase is associated with the secure key. Option
.B \-\-tries
specifies how often a passphrase can be re-entered. When option
.B \-\-key\-file
@@ -734,7 +745,7 @@ LUKS key slots is of less relevance.
For LUKS2 volumes, a passphrase is required. You are prompted for the
passphrase when running the generated commands, unless option
.B \-\-key\-file
is specified. Option
is specified, or a dummy passphrase is associated with the secure key. Option
.B \-\-tries
specifies how often a passphrase can be re-entered. When option
.B \-\-key\-file
@@ -1236,6 +1247,26 @@ system plugin (KMS plugin) is bound to the secure key repository. If the
repository is bound to a key management system plugin, then keys are generated
using the key management system by default.
.TP
.BR \-\-gen\-dummy\-passphrase
Generate a dummy passphrase randomly and associate it with the secure AES key
used to encrypt LUKS2 volume(s). The LUKS2 passphrase is of less or no relevance
for the security of the volume(s), when an secure AES key is used to encrypt the
volume(s), and can therefore be stored insecurely inside the secure key
repository. If for a certain usage the passphrase is of relevance for
security, then do not use this option. This option can only be specified for
keys with a volume type of \fBluks2\fP.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-set\-dummy\-passphrase\~\fIpassphrase\-file\fP
Set a dummy passphrase that is read from the specified file and associate it
with the secure AES key used to encrypt LUKS2 volume(s). The LUKS2 passphrase
is of less or no relevance for the security of the volume(s), when an secure
AES key is used to encrypt the volume(s), and can therefore be stored insecurely
inside the secure key repository. If for a certain usage the passphrase is of
relevance for security, then do not use this option. This option can only be
specified for keys with a volume type of \fBluks2\fP.
This option is only used for secure keys contained in the secure key repository.
.TP
.B KMS-plugin specific options
A key management system plugin may offer and even require plugin specific
options that can be specified with the generate command when the secure key
@@ -1372,6 +1403,26 @@ This option is only available if
has been compiled with LUKS2 support enabled. If LUKS2 support is not enabled,
the default volume type is \fBplain\fP.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-gen\-dummy\-passphrase
Generate a dummy passphrase randomly and associate it with the secure AES key
used to encrypt LUKS2 volume(s). The LUKS2 passphrase is of less or no relevance
for the security of the volume(s), when an secure AES key is used to encrypt the
volume(s), and can therefore be stored insecurely inside the secure key
repository. If for a certain usage the passphrase is of relevance for
security, then do not use this option. This option can only be specified for
keys with a volume type of \fBluks2\fP.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-set\-dummy\-passphrase\~\fIpassphrase\-file\fP
Set a dummy passphrase that is read from the specified file and associate it
with the secure AES key used to encrypt LUKS2 volume(s). The LUKS2 passphrase
is of less or no relevance for the security of the volume(s), when an secure
AES key is used to encrypt the volume(s), and can therefore be stored insecurely
inside the secure key repository. If for a certain usage the passphrase is of
relevance for security, then do not use this option. This option can only be
specified for keys with a volume type of \fBluks2\fP.
This option is only used for secure keys contained in the secure key repository.
.
.
.
@@ -1523,6 +1574,47 @@ This option is only available if
.B zkey
has been compiled with LUKS2 support enabled.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-gen\-dummy\-passphrase
Generate a dummy passphrase randomly and associate it with the secure AES key
used to encrypt LUKS2 volume(s). The LUKS2 passphrase is of less or no relevance
for the security of the volume(s), when an secure AES key is used to encrypt the
volume(s), and can therefore be stored insecurely inside the secure key
repository. If for a certain usage the passphrase is of relevance for
security, then do not use this option. This option can only be specified for
keys with a volume type of \fBluks2\fP. When there is already a dummy
passphrase associated with the key, you muts first remove the dummy passphrase
with option \fB\-\-remove\-dummy\-passphrase\fP before you can associate a new
dummy passphrase.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-set\-dummy\-passphrase\~\fIpassphrase\-file\fP
Set a dummy passphrase that is read from the specified file and associate it
with the secure AES key used to encrypt LUKS2 volume(s). The LUKS2 passphrase
is of less or no relevance for the security of the volume(s), when an secure
AES key is used to encrypt the volume(s), and can therefore be stored insecurely
inside the secure key repository. If for a certain usage the passphrase is of
relevance for security, then do not use this option. This option can only be
specified for keys with a volume type of \fBluks2\fP. When there is already a
dummy passphrase associated with the key, you muts first remove the dummy
passphrase with option \fB\-\-remove\-dummy\-passphrase\fP before you can
associate a new dummy passphrase.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-remove\-dummy\-passphrase
Remove the associated dummy passphrase used with LUKS2 volume(s).
The user is prompted to confirm the removal of the associated dummy passphrase.
Use the \fB\-\-force\fP option to remove the associated dummy passphrase without
prompting for a confirmation.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-F ", " \-\-force\fP
The user is prompted to confirm the removal of the associated dummy passphrase.
Use this option to remove the associated dummy passphrase without prompting for
a confirmation.
This option is only used for secure keys contained in the secure key repository,
and can only be specified together with option
\fB\-\-remove\-dummy\-passphrase\fP.
.
.
.
@@ -1590,8 +1682,9 @@ has been compiled with LUKS2 support enabled.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-\-key\-file\~\fIfile\-name\fP
Reads the passphrase from the specified file. If this option is omitted, then
you are prompted to enter the passphrase interactively during system startup.
Reads the passphrase from the specified file. If this option is omitted, and
no dummy passphrase is associated with the secure key, then you are prompted to
enter the passphrase interactively during system startup.
This option is passed to the generated crypttab entries for LUKS2 volumes, and
is only available if
.B zkey
@@ -1677,10 +1770,11 @@ option, and is only available if
has been compiled with LUKS2 support enabled.
.TP
.BR \-\-key\-file\~\fIfile\-name\fP
Reads the passphrase from the specified file. If this option is omitted,
or if the file\-name is \fI-\fP (a dash), then you are prompted to enter the
passphrase interactively. This option is passed to the generated command(s)
for LUKS2 volumes, and is only available if
Reads the passphrase from the specified file. If this option is omitted, and
no dummy passphrase is associated with the secure key, or if the file\-name is
\fI-\fP (a dash), then you are prompted to enter the passphrase interactively.
This option is passed to the generated command(s) for LUKS2 volumes, and is
only available if
.B zkey
has been compiled with LUKS2 support enabled.
.TP

View File

@@ -79,6 +79,9 @@ static struct zkey_globals {
char *key_type;
char *label;
bool local;
bool gen_passphrase;
char *passphrase_file;
bool remove_passphrase;
bool kms_bound;
bool run;
bool batch_mode;
@@ -156,6 +159,9 @@ static struct zkey_globals {
#define OPT_NO_APQN_CHECK 262
#define OPT_NO_VOLUME_CHECK 263
#define OPT_REFRESH_PROPERTIES 264
#define OPT_GEN_DUMMY_PASSPHRASE 265
#define OPT_SET_DUMMY_PASSPHRASE 266
#define OPT_REMOVE_DUMMY_PASSPHRASE 267
/*
* Configuration of command line options
@@ -271,6 +277,31 @@ static struct util_opt opt_vec[] = {
"generated by the KMS per default.",
.command = COMMAND_GENERATE,
},
{
.option = { "gen-dummy-passphrase", 0, NULL,
OPT_GEN_DUMMY_PASSPHRASE},
.desc = "Generate a dummy passphrase and associate it with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_GENERATE,
},
{
.option = { "set-dummy-passphrase", required_argument, NULL,
OPT_SET_DUMMY_PASSPHRASE},
.argument = "passphrase-file",
.desc = "Set a dummy passphrase to be associated with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_GENERATE,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
@@ -429,6 +460,31 @@ static struct util_opt opt_vec[] = {
.command = COMMAND_IMPORT,
},
#endif
{
.option = { "gen-dummy-passphrase", 0, NULL,
OPT_GEN_DUMMY_PASSPHRASE},
.desc = "Generate a dummy passphrase and associate it with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_IMPORT,
},
{
.option = { "set-dummy-passphrase", required_argument, NULL,
OPT_SET_DUMMY_PASSPHRASE},
.argument = "passphrase-file",
.desc = "Set a dummy passphrase to be associated with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_IMPORT,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
@@ -593,6 +649,45 @@ static struct util_opt opt_vec[] = {
.command = COMMAND_CHANGE,
},
#endif
{
.option = { "gen-dummy-passphrase", 0, NULL,
OPT_GEN_DUMMY_PASSPHRASE},
.desc = "Generate a dummy passphrase and associate it with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_CHANGE,
},
{
.option = { "set-dummy-passphrase", required_argument, NULL,
OPT_SET_DUMMY_PASSPHRASE},
.argument = "passphrase-file",
.desc = "Set a dummy passphrase to be associated with the "
"secure AES key used to encrypt LUKS2 volume(s). The "
"LUKS2 passphrase is of less or no relevance for the "
"security of the volume(s), when an secure AES key is "
"used to encrypt the volume(s), and can therefore be "
"stored insecurely inside the secure key repository.",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_CHANGE,
},
{
.option = { "remove-dummy-passphrase", 0, NULL,
OPT_REMOVE_DUMMY_PASSPHRASE},
.desc = "Remove an associated dummy passphrase used with LUKS2 "
"volume(s).",
.flags = UTIL_OPT_FLAG_NOSHORT,
.command = COMMAND_CHANGE,
},
{
.option = {"force", 0, NULL, 'F'},
.desc = "Do not prompt for a confirmation when removing an "
"associated dummy passphrase",
.command = COMMAND_CHANGE,
},
/***********************************************************/
{
.flags = UTIL_OPT_FLAG_SECTION,
@@ -1631,6 +1726,14 @@ static int command_generate_repository(void)
if (g.sector_size < 0)
g.sector_size = 0;
if (g.gen_passphrase && g.passphrase_file != NULL) {
warnx("Either '--gen-dummy-passphrase' or "
"'--set-dummy-passphrase' can be specified, but not "
"both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.kms_info.plugin_lib != NULL && !g.local) {
if (g.apqns != NULL) {
warnx("Option '--apqns|-a' is not valid for "
@@ -1655,6 +1758,8 @@ static int command_generate_repository(void)
g.description, g.volumes,
g.sector_size, g.keybits, g.xts,
g.volume_type, g.key_type,
g.gen_passphrase,
g.passphrase_file,
g.kms_options,
g.num_kms_options);
goto out;
@@ -1666,7 +1771,8 @@ static int command_generate_repository(void)
rc = keystore_generate_key(g.keystore, g.name, g.description, g.volumes,
g.apqns, g.noapqncheck, g.sector_size,
g.keybits, g.xts, g.clearkeyfile,
g.volume_type, g.key_type, g.pkey_fd);
g.volume_type, g.key_type, g.gen_passphrase,
g.passphrase_file, g.pkey_fd);
out:
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
@@ -1729,6 +1835,18 @@ static int command_generate(void)
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.gen_passphrase) {
warnx("Option '--gen-dummy-passphrase' is not valid "
"for generating a key outside of the repository");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.passphrase_file != NULL) {
warnx("Option '--sen-dummy-passphrase' is not valid "
"for generating a key outside of the repository");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
rc = cross_check_apqns(NULL, NULL,
get_min_card_level_for_keytype(g.key_type),
@@ -2111,10 +2229,19 @@ static int command_import(void)
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.gen_passphrase && g.passphrase_file != NULL) {
warnx("Either '--gen-dummy-passphrase' or "
"'--set-dummy-passphrase' can be specified, but not "
"both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
rc = keystore_import_key(g.keystore, g.name, g.description, g.volumes,
g.apqns, g.noapqncheck, g.sector_size,
g.pos_arg, g.volume_type, &g.lib);
g.pos_arg, g.volume_type, g.gen_passphrase,
g.passphrase_file, &g.lib);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -2200,10 +2327,39 @@ static int command_change(void)
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.gen_passphrase && g.passphrase_file != NULL) {
warnx("Either '--gen-dummy-passphrase' or "
"'--set-dummy-passphrase' can be specified, but not "
"both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.gen_passphrase && g.remove_passphrase) {
warnx("Either '--gen-dummy-passphrase' or "
"'--remove-dummy-passphrase' can be specified, but not "
"both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.passphrase_file != NULL && g.remove_passphrase) {
warnx("Either '--set-dummy-passphrase' or "
"'--remove-dummy-passphrase' can be specified, but not "
"both");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
if (g.force && !g.remove_passphrase) {
warnx("Option '--force|-F' is only valid together with "
"the '--remove-dummy-passphrase' option");
util_prg_print_parse_error();
return EXIT_FAILURE;
}
rc = keystore_change_key(g.keystore, g.name, g.description, g.volumes,
g.apqns, g.noapqncheck, g.sector_size,
g.volume_type);
g.volume_type, g.gen_passphrase,
g.passphrase_file, g.remove_passphrase,
g.force);
return rc != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -3056,6 +3212,15 @@ int main(int argc, char *argv[])
case 'P':
g.refresh_properties = 1;
break;
case OPT_GEN_DUMMY_PASSPHRASE:
g.gen_passphrase = 1;
break;
case OPT_SET_DUMMY_PASSPHRASE:
g.passphrase_file = optarg;
break;
case OPT_REMOVE_DUMMY_PASSPHRASE:
g.remove_passphrase = 1;
break;
case 'h':
print_help(command, sub_command);
return EXIT_SUCCESS;