Re: [PATCH] mm: mmap_lock: fix use-after-free race and css ref leak in tracepoints

From: Tejun Heo
Date: Wed Dec 02 2020 - 14:01:55 EST


Hello,

On Tue, Dec 01, 2020 at 12:53:46PM -0800, Shakeel Butt wrote:
> The writeback tracepoint in include/trace/events/writeback.h is
> already using the cgroup IDs. Actually it used to use cgroup_path but
> converted to cgroup_ino.
>
> Tejun, how do you use these tracepoints?

There've been some changes to cgroup ids recently and now cgroup id, ino and
its file_handle are all compatible. On 64bit ino machines, they're all the
same and won't be reused. On 32bit ino machines, the lower 32bit of full id
is used as ino. ino may be reused but not the full 64bit id.

You can map back cgroup id to path from userspace using open_by_handle_at().
The following is an example program which does path -> cgrp id -> path
mappings.

#define _GNU_SOURCE
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>

#ifndef FILEID_KERNFS
#define FILEID_KERNFS 0xfe
#endif

struct fh_store {
struct file_handle fh;
char stor[MAX_HANDLE_SZ];
};

uint64_t path_to_cgrp_id(const char *path)
{
struct fh_store fh_store;
struct file_handle *fh = &fh_store.fh;
int mnt_id;

fh->handle_bytes = MAX_HANDLE_SZ;

if (name_to_handle_at(AT_FDCWD, path, fh, &mnt_id, 0)) {
perror("name_to_handle_at");
abort();
}

if (fh->handle_type != FILEID_KERNFS) {
fprintf(stderr, "invalid handle_type 0x%x\n", fh->handle_type);
abort();
}

return *(uint64_t *)fh->f_handle;
}

void cgrp_id_to_path(uint64_t cgrp_id, char *path_buf)
{
struct fh_store fh_store;
struct file_handle *fh = &fh_store.fh;
char proc_path[PATH_MAX];
int mnt_fd, fd;

fh->handle_type = FILEID_KERNFS;
fh->handle_bytes = sizeof(uint64_t);
*(uint64_t *)fh->f_handle = cgrp_id;

mnt_fd = open("/sys/fs/cgroup", O_RDONLY);
if (mnt_fd < 0) {
perror("open(\"/sys/fs/cgroup\")");
abort();
}

fd = open_by_handle_at(mnt_fd, fh, O_RDONLY);
if (fd < 0) {
perror("open_by_handle_at");
abort();
}

snprintf(proc_path, PATH_MAX, "/proc/self/fd/%d", fd);
printf("proc_path=%s\n", proc_path);

if (readlink(proc_path, path_buf, PATH_MAX) < 0) {
perror("readlink");
abort();
}
}

int main(int argc, char **argv)
{
char path_buf[PATH_MAX + 1] = "";
uint64_t cgrp_id;

if (argc != 2) {
fprintf(stderr, "Usage: test-cgrp-id CGROUP_PATH\n");
return 1;
}

cgrp_id = path_to_cgrp_id(argv[1]);
printf("cgrp_id=%llu\n", (unsigned long long)cgrp_id);

cgrp_id_to_path(cgrp_id, path_buf);
printf("cgrp_path=%s\n", path_buf);

return 0;
}