Пример #1
0
TError TContainerHolder::RestoreId(const kv::TNode &node, int &id) {
    std::string value = "";

    TError error = Storage->Get(node, P_RAW_ID, value);
    if (error) {
        // FIXME before v1.0 we didn't store id for meta or stopped containers;
        // don't try to recover, just assign new safe one
        error = IdMap.Get(id);
        if (error)
            return error;
        L_WRN() << "Couldn't restore container id, using " << id << std::endl;
    } else {
        error = StringToInt(value, id);
        if (error)
            return error;

        error = IdMap.GetAt(id);
        if (error) {
            // FIXME before v1.0 there was a possibility for two containers
            // to use the same id, allocate new one upon restore we see this

            error = IdMap.Get(id);
            if (error)
                return error;
            L_WRN() << "Container ids clashed, using new " << id << std::endl;
        }
        return error;
    }

    return TError::Success();
}
Пример #2
0
void InitCred() {
    TError error;

    error = GroupId(PORTO_GROUP_NAME, PortoGroup);
    if (error)
        L_WRN() << "Cannot find group porto: " << error << std::endl;

    if (TPath("/proc/sys/kernel/cap_last_cap").ReadInt(LastCapability)) {
        L_WRN() << "Can't read /proc/sys/kernel/cap_last_cap, assuming 36" << std::endl;
        LastCapability = 36; //FIXME
    }
}
Пример #3
0
TError TClient::IdentifyClient(TContainerHolder &holder, bool initial) {
    std::shared_ptr<TContainer> ct;
    struct ucred cr;
    socklen_t len = sizeof(cr);
    TError error;

    if (getsockopt(Fd, SOL_SOCKET, SO_PEERCRED, &cr, &len))
        return TError(EError::Unknown, errno, "Cannot identify client: getsockopt() failed");

    /* check that request from the same pid and container is still here */
    if (!initial && Pid == cr.pid && TaskCred.Uid == cr.uid &&
            TaskCred.Gid == cr.gid && !ClientContainer.expired())
        return TError::Success();

    TaskCred.Uid = cr.uid;
    TaskCred.Gid = cr.gid;
    Pid = cr.pid;

    error = holder.FindTaskContainer(Pid, ct);
    if (error && error.GetErrno() != ENOENT)
        L_WRN() << "Cannot identify container of pid " << Pid
                << " : " << error << std::endl;
    if (error)
        return error;

    if (!ct->IsPortoEnabled())
        return TError(EError::Permission,
                      "Porto disabled in container " + ct->GetName());

    ClientContainer = ct;

    error = TPath("/proc/" + std::to_string(Pid) + "/comm").ReadAll(Comm, 64);
    if (error)
        Comm = "<unknown process>";
    else
        Comm.resize(Comm.length() - 1); /* cut \n at the end */

    if (ct->IsRoot()) {
        Cred.Uid = cr.uid;
        Cred.Gid = cr.gid;
        error = LoadGroups();
        if (error && error.GetErrno() != ENOENT)
            L_WRN() << "Cannot load supplementary group list" << Pid
                    << " : " << error << std::endl;
    } else {
        /* requests from containers are executed in behalf of their owners */
        Cred = ct->OwnerCred;
    }

    ReadOnlyAccess = !Cred.IsPortoUser();

    return TError::Success();
}
Пример #4
0
TError TClient::AcceptConnection(TContext &context, int listenFd) {
    struct sockaddr_un peer_addr;
    socklen_t peer_addr_size;
    TError error;

    peer_addr_size = sizeof(struct sockaddr_un);
    Fd = accept4(listenFd, (struct sockaddr *) &peer_addr,
                 &peer_addr_size, SOCK_NONBLOCK | SOCK_CLOEXEC);
    if (Fd < 0) {
        error = TError(EError::Unknown, errno, "accept4()");
        if (error.GetErrno() != EAGAIN)
            L_WRN() << "Cannot accept client: " << error << std::endl;
        return error;
    }

    error = IdentifyClient(*context.Cholder, true);
    if (error) {
        close(Fd);
        Fd = -1;
        return error;
    }

    if (Verbose)
        L() << "Client connected: " << *this << std::endl;

    return TError::Success();
}
Пример #5
0
TError TClient::IdentifyClient(TContainerHolder &holder, bool initial) {
    struct ucred cr;
    socklen_t len = sizeof(cr);
    TError error;

    if (getsockopt(Fd, SOL_SOCKET, SO_PEERCRED, &cr, &len))
        return TError(EError::Unknown, errno, "Cannot identify client: getsockopt() failed");

    if (!initial && Pid == cr.pid && Cred.Uid == cr.uid && Cred.Gid == cr.gid &&
            !ClientContainer.expired())
        return TError::Success();

    Cred.Uid = cr.uid;
    Cred.Gid = cr.gid;
    Pid = cr.pid;

    error = TPath("/proc/" + std::to_string(Pid) + "/comm").ReadAll(Comm, 64);
    if (error)
        Comm = "<unknown process>";
    else
        Comm.resize(Comm.length() - 1); /* cut \n at the end */

    error = LoadGroups();
    if (error && error.GetErrno() != ENOENT)
        L_WRN() << "Cannot load supplementary group list" << Pid
                << " : " << error << std::endl;

    ReadOnlyAccess = !Cred.IsPortoUser();

    std::shared_ptr<TContainer> container;
    error = holder.FindTaskContainer(Pid, container);
    if (error && error.GetErrno() != ENOENT)
        L_WRN() << "Cannot identify container of pid " << Pid
                << " : " << error << std::endl;
    if (error)
        return error;

    if (!container->Prop->Get<bool>(P_ENABLE_PORTO))
        return TError(EError::Permission, "Porto disabled in container " + container->GetName());

    ClientContainer = container;
    return TError::Success();
}
Пример #6
0
TError TClient::Identify(TContainerHolder &holder, bool full) {
    struct ucred cr;
    socklen_t len = sizeof(cr);

    if (getsockopt(Fd, SOL_SOCKET, SO_PEERCRED, &cr, &len) == 0) {
        if (full) {
            TFile f("/proc/" + std::to_string(cr.pid) + "/comm");
            std::string comm;

            if (f.AsString(comm))
                comm = "unknown process";

            comm.erase(std::remove(comm.begin(), comm.end(), '\n'), comm.end());

            Pid = cr.pid;
            Comm = comm;

            TError err = LoadGroups();
            if (err) {
                L_WRN() << "Can't load supplementary group list" << cr.pid
                    << " : " << err << std::endl;
            }

            err = IdentifyContainer(holder);
            if (err) {
                L_WRN() << "Can't identify container of pid " << cr.pid
                        << " : " << err << std::endl;
                return err;
            }
        } else {
            if (Container.expired())
                return TError(EError::Unknown, "Can't identify client (container is dead)");
        }

        Cred.Uid = cr.uid;
        Cred.Gid = cr.gid;

        return TError::Success();
    } else {
        return TError(EError::Unknown, "Can't identify client (getsockopt() failed)");
    }
}
Пример #7
0
TError TClient::ReadRequest(rpc::TContainerRequest &request) {
    TScopedLock lock(Mutex);

    if (Processing) {
        L_WRN() << "Client request before response: " << *this << std::endl;
        return TError::Success();
    }

    if (Fd < 0)
        return TError(EError::Unknown, "Connection closed");

    if (Offset >= Buffer.size())
        Buffer.resize(Offset + 4096);

    ssize_t len = recv(Fd, &Buffer[Offset], Buffer.size() - Offset, MSG_DONTWAIT);
    if (len > 0)
        Offset += len;
    else if (len == 0)
        return TError(EError::Unknown, "recv return zero");
    else if (errno != EAGAIN && errno != EWOULDBLOCK)
        return TError(EError::Unknown, errno, "recv request failed");

    if (Length && Offset < Length)
        return TError::Queued();

    google::protobuf::io::CodedInputStream input(&Buffer[0], Offset);

    uint32_t length;
    if (!input.ReadVarint32(&length))
        return TError::Queued();

    if (!Length) {
        if (length > config().daemon().max_msg_len())
            return TError(EError::Unknown, "oversized request: " + std::to_string(length));

        Length = length + google::protobuf::io::CodedOutputStream::VarintSize32(length);
        if (Buffer.size() < Length)
            Buffer.resize(Length + 4096);

        if (Offset < Length)
            return TError::Queued();
    }

    if (!request.ParseFromCodedStream(&input))
        return TError(EError::Unknown, "cannot parse request");

    if (Offset > Length)
        return TError(EError::Unknown, "garbage after request");

    Processing = true;
    return EpollLoop->StopInput(Fd);
}