diff options
author | YunQiang Su <syq@debian.org> | 2018-12-25 12:01:17 +0100 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2019-01-03 15:04:08 +0100 |
commit | f5855697aa19fb92637e72ab02e4623abe77f288 (patch) | |
tree | 5e4cd164cf2d93696d5c5388d38db73e386279bc /src/core/cgroup.c | |
parent | Merge pull request #11273 from pseyfert/zsh-debugger-completion (diff) | |
download | systemd-f5855697aa19fb92637e72ab02e4623abe77f288.tar.xz systemd-f5855697aa19fb92637e72ab02e4623abe77f288.zip |
Pass separate dev_t var to device_path_parse_major_minor
MIPS/O32's st_rdev member of struct stat is unsigned long, which
is 32bit, while dev_t is defined as 64bit, which make some problems
in device_path_parse_major_minor.
Don't pass st.st_rdev, st_mode to device_path_parse_major_minor,
while pass 2 seperate variables. The result of stat is alos copied
out into these 2 variables. Fixes: #11247
Diffstat (limited to 'src/core/cgroup.c')
-rw-r--r-- | src/core/cgroup.c | 35 |
1 files changed, 22 insertions, 13 deletions
diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 7b817dc225..ed2f331b33 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -396,26 +396,31 @@ static void cgroup_xattr_apply(Unit *u) { } static int lookup_block_device(const char *p, dev_t *ret) { - struct stat st = {}; + dev_t rdev, dev = 0; + mode_t mode; int r; assert(p); assert(ret); - r = device_path_parse_major_minor(p, &st.st_mode, &st.st_rdev); + r = device_path_parse_major_minor(p, &mode, &rdev); if (r == -ENODEV) { /* not a parsable device node, need to go to disk */ + struct stat st; if (stat(p, &st) < 0) return log_warning_errno(errno, "Couldn't stat device '%s': %m", p); + rdev = (dev_t)st.st_rdev; + dev = (dev_t)st.st_dev; + mode = st.st_mode; } else if (r < 0) return log_warning_errno(r, "Failed to parse major/minor from path '%s': %m", p); - if (S_ISCHR(st.st_mode)) { + if (S_ISCHR(mode)) { log_warning("Device node '%s' is a character device, but block device needed.", p); return -ENOTBLK; - } else if (S_ISBLK(st.st_mode)) - *ret = st.st_rdev; - else if (major(st.st_dev) != 0) - *ret = st.st_dev; /* If this is not a device node then use the block device this file is stored on */ + } else if (S_ISBLK(mode)) + *ret = rdev; + else if (major(dev) != 0) + *ret = dev; /* If this is not a device node then use the block device this file is stored on */ else { /* If this is btrfs, getting the backing block device is a bit harder */ r = btrfs_get_block_device(p, ret); @@ -436,7 +441,8 @@ static int lookup_block_device(const char *p, dev_t *ret) { } static int whitelist_device(BPFProgram *prog, const char *path, const char *node, const char *acc) { - struct stat st = {}; + dev_t rdev; + mode_t mode; int r; assert(path); @@ -445,11 +451,12 @@ static int whitelist_device(BPFProgram *prog, const char *path, const char *node /* Some special handling for /dev/block/%u:%u, /dev/char/%u:%u, /run/systemd/inaccessible/chr and * /run/systemd/inaccessible/blk paths. Instead of stat()ing these we parse out the major/minor directly. This * means clients can use these path without the device node actually around */ - r = device_path_parse_major_minor(node, &st.st_mode, &st.st_rdev); + r = device_path_parse_major_minor(node, &mode, &rdev); if (r < 0) { if (r != -ENODEV) return log_warning_errno(r, "Couldn't parse major/minor from device path '%s': %m", node); + struct stat st; if (stat(node, &st) < 0) return log_warning_errno(errno, "Couldn't stat device %s: %m", node); @@ -457,22 +464,24 @@ static int whitelist_device(BPFProgram *prog, const char *path, const char *node log_warning("%s is not a device.", node); return -ENODEV; } + rdev = (dev_t) st.st_rdev; + mode = st.st_mode; } if (cg_all_unified() > 0) { if (!prog) return 0; - return cgroup_bpf_whitelist_device(prog, S_ISCHR(st.st_mode) ? BPF_DEVCG_DEV_CHAR : BPF_DEVCG_DEV_BLOCK, - major(st.st_rdev), minor(st.st_rdev), acc); + return cgroup_bpf_whitelist_device(prog, S_ISCHR(mode) ? BPF_DEVCG_DEV_CHAR : BPF_DEVCG_DEV_BLOCK, + major(rdev), minor(rdev), acc); } else { char buf[2+DECIMAL_STR_MAX(dev_t)*2+2+4]; sprintf(buf, "%c %u:%u %s", - S_ISCHR(st.st_mode) ? 'c' : 'b', - major(st.st_rdev), minor(st.st_rdev), + S_ISCHR(mode) ? 'c' : 'b', + major(rdev), minor(rdev), acc); /* Changing the devices list of a populated cgroup might result in EINVAL, hence ignore EINVAL here. */ |