From edaad2a92738f9b10c73e3f70d36f68ab27cd523 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Thu, 5 Apr 2018 16:55:32 +0200 Subject: [PATCH] chreipl: correct read-only attributes handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit chreipl could only be used as root (effective userid 0), which is explicitly checked upon invocation. "access" call is a wrong method to check super user read/write access for sysfs files, because it is simply always returns 0 (success), despite actual sysfs file permissions or underlying sysfs file callbacks setup. The only guaranteed way of checking sysfs file super user access is an actual open call with the corresponding access mode. The problem is that chreipl always tries to update some sysfs attributes even through they are not specified as command line arguments. Together with a broken sysfs file access checks this leads to inability to use the tool, when some sysfs attributes are read-only (which is the case on older systems where diag308 set does not work). $ chreipl ccw -d 0.0.ec5a chreipl: Could not open "reipl/ccw/parm" (Permission denied) The change fixes access checks, which are in place to handle "diag308 set does not work" case (presence of read-only sysfs attributes). Also replaces R_OK with F_OK in "set_target_type_auto" to underline that only file presence is checked, not an actual read access. Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik Signed-off-by: Jan Höppner --- ipl_tools/cmd_chreipl.c | 73 +++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/ipl_tools/cmd_chreipl.c b/ipl_tools/cmd_chreipl.c index 89a2e7b8..5ba0b224 100644 --- a/ipl_tools/cmd_chreipl.c +++ b/ipl_tools/cmd_chreipl.c @@ -445,7 +445,7 @@ static void set_target_type_auto(const char *arg) { char busid[10]; - if (access(arg, R_OK) == 0) { + if (access(arg, F_OK) == 0) { set_target_type(TT_NODE, 1); return; } @@ -539,12 +539,19 @@ static void parse_chreipl_options(int argc, char *argv[]) parse_pos_args(&argv[optind], argc - optind); } -static void verify_write_access(const char *path, const char *attr) +static void check_exists(const char *path, const char *attr) { char fpath[PATH_MAX]; snprintf(fpath, sizeof(fpath), "/sys/firmware/%s", path); - if (access(fpath, W_OK) != 0) + if (access(fpath, F_OK) != 0) + ERR_EXIT("System does not allow to set %s", attr); +} + +static void write_str_optional(char *string, char *file, int exit_on_fail, + const char *attr) +{ + if (write_str_errno(string, file) && exit_on_fail) ERR_EXIT("System does not allow to set %s", attr); } @@ -585,22 +592,18 @@ static void chreipl_ccw(void) ERR_EXIT("Could not find DASD CCW device \"%s\"", l.busid); } + if (l.bootparms_set && strlen(l.bootparms) > BOOTPARMS_CCW_MAX) { + ERR_EXIT("Maximum boot parameter length exceeded (%zu/%u)", + strlen(l.bootparms), BOOTPARMS_CCW_MAX); + } + /* * On old systems that use CCW reipl loadparm cannot be set */ - if (l.loadparm_set) - verify_write_access("reipl/ccw/loadparm", "loadparm"); - if (l.bootparms_set) { - verify_write_access("reipl/ccw/parm", "boot parameters"); - if (strlen(l.bootparms) > BOOTPARMS_CCW_MAX) - ERR_EXIT("Maximum boot parameter length exceeded " - "(%zu/%u)", strlen(l.bootparms), - BOOTPARMS_CCW_MAX); - } - if (access("/sys/firmware/reipl/ccw/parm", W_OK) == 0) - write_str(l.bootparms, "reipl/ccw/parm"); - if (access("/sys/firmware/reipl/ccw/loadparm", W_OK) == 0) - write_str(l.loadparm, "reipl/ccw/loadparm"); + write_str_optional(l.loadparm, "reipl/ccw/loadparm", l.loadparm_set, + "loadparm"); + write_str_optional(l.bootparms, "reipl/ccw/parm", l.bootparms_set, + "boot parameters"); write_str(l.busid, "reipl/ccw/device"); write_str("ccw", "reipl/reipl_type"); @@ -616,23 +619,18 @@ static void chreipl_fcp(void) ERR_EXIT("Device is on cio_ignore list, try \"cio_ignore -r %s\"?", l.busid); ERR_EXIT("Could not find FCP device \"%s\"", l.busid); } - verify_write_access("reipl/fcp/device", "\"fcp\" re-IPL target"); + check_exists("reipl/fcp/device", "\"fcp\" re-IPL target"); + if (l.bootparms_set && strlen(l.bootparms) > BOOTPARMS_FCP_MAX) { + ERR_EXIT("Maximum boot parameter length exceeded (%zu/%u)", + strlen(l.bootparms), BOOTPARMS_FCP_MAX); + } /* * On old systems the FCP reipl loadparm cannot be set */ - if (l.loadparm_set) - verify_write_access("reipl/fcp/loadparm", "loadparm"); - if (l.bootparms_set) { - verify_write_access("reipl/fcp/scp_data", "boot parameters"); - if (strlen(l.bootparms) > BOOTPARMS_FCP_MAX) - ERR_EXIT("Maximum boot parameter length exceeded " - "(%zu/%u)", strlen(l.bootparms), - BOOTPARMS_FCP_MAX); - } - if (access("/sys/firmware/reipl/fcp/scp_data", W_OK) == 0) - write_str(l.bootparms, "reipl/fcp/scp_data"); - if (access("/sys/firmware/reipl/fcp/loadparm", W_OK) == 0) - write_str(l.loadparm, "reipl/fcp/loadparm"); + write_str_optional(l.loadparm, "reipl/fcp/loadparm", l.loadparm_set, + "loadparm"); + write_str_optional(l.bootparms, "reipl/fcp/scp_data", l.bootparms_set, + "boot parameters"); write_str(l.busid, "reipl/fcp/device"); write_str(l.wwpn, "reipl/fcp/wwpn"); write_str(l.lun, "reipl/fcp/lun"); @@ -652,17 +650,14 @@ static void chreipl_fcp(void) static void chreipl_nss(void) { check_nss_opts(); - verify_write_access("reipl/nss/name", "\"nss\" re-IPL target"); - if (l.bootparms_set) { - verify_write_access("reipl/nss/parm", "boot parameters"); - if (strlen(l.bootparms) > BOOTPARMS_NSS_MAX) - ERR_EXIT("Maximum boot parameter length exceeded " - "(%zu/%u)", strlen(l.bootparms), - BOOTPARMS_NSS_MAX); + check_exists("reipl/nss/name", "\"nss\" re-IPL target"); + if (l.bootparms_set && strlen(l.bootparms) > BOOTPARMS_NSS_MAX) { + ERR_EXIT("Maximum boot parameter length exceeded (%zu/%u)", + strlen(l.bootparms), BOOTPARMS_NSS_MAX); } + write_str_optional(l.bootparms, "reipl/nss/parm", l.bootparms_set, + "boot parameters"); write_str(l.nss_name, "reipl/nss/name"); - if (access("/sys/firmware/reipl/nss/parm", W_OK) == 0) - write_str(l.bootparms, "reipl/nss/parm"); write_str("nss", "reipl/reipl_type"); print_nss(0); }